These docs cover 0.2.0-beta.26. Each guide distinguishes supported beta behavior, explicit deployment boundaries, and retained 0.1 compatibility material.

Browse documentationAll guides

Build · core model

Components

A Presolve component is an exported class that extends Component and returns TSX from one instance render() method. Extending the base class is compiler evidence; there is no runtime component registry.

Define a component

import { Component } from "presolve";export class Welcome extends Component {name = "Ada";render() {return <section><h1>Hello, {this.name}</h1></section>;}}

Ordinary initialized fields are fixed component data. Use state() only when the value must change through an action. The compiler resolves every rendered binding to the owning component instance.

Inputs and defaults

Undecorated instance fields declare inputs. A definite-assignment field is required from the caller; an initializer supplies a default.

export class UserCard extends Component {user!: { name: string };compact = false;render() {return <article>{this.user.name}</article>;}}
Ownership rule

The component that declares a mutable state field owns its writes. A child can request a change through an explicit action input; it does not reach into its parent’s state.

Invoke components

Use a local or imported PascalCase class directly in TSX. The compiler resolves the class, invocation, input bindings, instance identity, and nested lifecycle.

export class ProfilePage extends Component {profile = { name: "Ada" };render() {return <main><UserCard user={this.profile} /></main>;}}

Conditional and keyed structure

A conditional creates one compiler-owned structural host. A keyed map() retains identity by key while items reorder, appear, or leave.

return <section>{this.visible ? <ProfileCard /> : <p>Hidden</p>}<ul>{this.items.map((item) =><li key={item.id}>{item.label}</li>)}</ul></section>;
Empty branches are structural

Use condition && <Panel /> or condition ? (<Panel />) : null when the false branch should emit no DOM. Presolve publishes an empty false fragment and materializes the true branch through the same compiler-owned host.

InsertMaterialize the admitted branch or keyed item and activate its exact bindings.
RetainPreserve the component instance and owned state when its key survives a reorder.
RemoveRun effect cleanup and child teardown before releasing the parent occurrence.

Identity and teardown

Instance identity is not inferred from DOM position at runtime. Static, conditional, keyed, nested, and slot-projected occurrences receive compiler-issued ownership. This makes retention and child-first teardown deterministic across cold execution and resume.

Beta limits

  • Component classes must resolve statically; dynamic component expressions are outside the beta.
  • Constructors, mixins, and runtime registries do not establish component semantics.
  • Keyed lists require an admitted map() shape and stable primitive keys.
  • Unsupported control flow fails during pnpm check; Presolve does not switch to generic reconciliation.