ilokesto

Core concepts

@ilokesto/form is easiest to understand as a small controller around normalized field records. A CreateForm instance accepts initial values, splits leaf values into FieldState records, and reconstructs the object when you call getValues(). Framework adapters subscribe to that controller and expose binding shapes that feel natural for their renderer.

Framework independence

The root package exports CreateForm and core types. It has no React, Vue, Solid, Svelte, or DOM runtime import. That separation lets you create forms in shared modules, test the core directly, and choose a framework adapter only at the component boundary. Adapters depend on the Form<TValues> interface: getState, subscribe, value operations, validation operations, array operations, and submit/reset commands.

Tuple paths, not dot paths

FieldPathInput is string | FieldPath. A string is a literal name. A tuple is a nested path. This rule is more explicit than dot parsing and avoids surprises with names like user.email that should remain a single field.

form.setValue(['user', 'email'], 'ada@example.com');
form.setValue('user.email', 'literal top-level value');

Field state and metadata

Every field has value, errors, touched, dirty, and modified. dirty compares the current value with the initial value. modified records whether a user-originated write happened. touched is set by blur(). These flags power UI decisions without forcing every framework adapter to invent its own metadata model.

Validation and Standard Schema

Form-level schema and field-local schemas both use StandardSchemaV1. Field-local schemas are registered through adapter options or registerFieldSchema and take precedence for that field. validateOn supports change, blur, submit, and manual; manual validation is always available through trigger().

Arrays and rebasing

array(path) returns commands that update array values and rebase child field metadata. When you move, swap, insert, or remove, errors and touched state should follow the logical item rather than stay glued to a numeric index. Stable keys() support list rendering while this rebasing happens.

On this page