Reactivity and Lifecycle
Reactive getters, imperative snapshots, dynamic bindings, and owner cleanup.
Reactivity and Lifecycle
Create primitives inside a Solid component or createRoot. Every primitive requires a Solid owner; calling one without an owner throws. The owner releases subscriptions and owned field refs on disposal. Core values and issues remain available after disposal.
Reactive Reads
The public API, its methods, and its state, status, and input-prop containers keep their identities. Their reactive getters update independently: a sibling field change does not rerun a consumer of another field's value, and status-only updates do not rerun value consumers.
| Read | Behavior |
|---|---|
form.status.valid, form.status.submitting | Reactive status properties. |
field.id, field.value, field.state.*, field.props.value | Reactive field properties. |
array.state.*, array.ids | Reactive array properties. |
form.values, field.get(), array.get(), field.issues() | Imperative snapshots. |
createFieldApi(...).state | Imperative field state; subscribe explicitly. |
Read getters in JSX or a tracking scope. Destructuring a reactive property captures its current value. Keeping a reference to the state container preserves its getters:
import { , , } from '@oxform/solid';
import { } from 'zod';
function () {
const = ({ : .({ : .() }), : { : '' } });
const = ({ , : 'email' });
const = .;
const = (, => ..);
return (
<>
< {....} />
<>
{.} / {()}
</>
</>
);
}Spread field.props directly in JSX. Copying it into a new object outside JSX captures its value getter's current result.
With @oxform/solid/v2, core writes remain synchronous, while reactive getters, selected accessors, and DOM output update at Solid's flush. The adapter does not flush automatically. Use imperative reads for the latest core value, or call flush() from solid-js before requiring committed reactive state. See Solid 2 timing.
Dynamic Options
Creation options accept a plain object, an object with reactive getters, or an accessor returning an object. createSubscribe and createFormEffect also accept an API accessor.
Changing a form's options updates configuration without resetting current values. Changed defaultValues become the next reset baseline. The form's ID, schema-derived value type, and inferred issue-level type stay fixed for its lifetime.
Changing a field or array's form or name switches its binding. Retained methods write to the current binding, subscriptions follow its store, and a registered field element moves to the new path.
In Solid 2, reactive option changes also wait for a flush. If you change a signal selecting a form or field name and then invoke a retained handler in the same operation, flush first so the handler uses the new binding.
import { , } from '@oxform/solid';
import { } from 'solid-js';
import { } from 'zod';
function () {
const = ({
: .({ : .(), : .() }),
: { : '', : '' },
});
const [, ] = <'primary' | 'secondary'>('primary');
const = (() => ({ , : () }));
return (
<>
< ='Selected address' {....} />
< ='button' ={() => ('secondary')}>
Edit secondary
</>
</>
);
}Components track their JSX form and name props using the same binding behavior. For keyed rows, derive the name from Solid's reactive index accessor; see Array fields.
Ref Ownership and Reset
Field cleanup clears a ref only if it still matches the element registered by that binding. It preserves an element registered later by another owner. Passing null to register is a no-op; unregister() explicitly clears the current ref.
Core reset clears refs by default. If a retained control should remain registered for later focus() and blur() calls, use form.reset({ keep: { refs: true } }). Reactive values still update when resetting.
Server Rendering
Server rendering reads initial state without creating store subscriptions or running createFormEffect callbacks. Create a form inside each component or request's owner to keep state separate between requests. Client owners subscribe and clean up normally.
For Solid 2 hydration, supply matching initial schema options and default values on the server and client. Validation and submission retain core promises and status flags; they do not suspend rendering.