API reference
useForm<M, R>()
Section titled “useForm<M, R>()”Creates a self-contained form store.
| Property | Type | Description |
|---|---|---|
Form |
Component | Renders the form element; accepts the same props as Form |
state |
FormState<M> |
Reactive state object |
store |
FormStore<M> |
Raw [state, mutations] tuple |
Use useForm when you need to read field values or validity outside the form tree. Use Form
directly when you only need a submit handler.
Pass a Standard Schema-compatible schema to infer values without a form generic:
const form = useForm({ schema: loginSchema });
<form.Form onSubmit={(values) => values.email}>{/* fields */}</form.Form>;A self-contained form that creates its own internal store.
<Form<LoginValues> onSubmit={handleSubmit} errors={['Server error']} isLoading={isPageLoading}> {/* fields */}</Form>
<Form schema={loginSchema} onSubmit={(values) => values.email}> {/* values inferred from loginSchema */}</Form>| Prop | Type | Description |
|---|---|---|
onSubmit |
(values: M) => void | Promise<void> |
Submit handler |
schema |
StandardSchemaV1 |
Optional Standard Schema-compatible validator; successful output is passed to onSubmit |
children |
JSX.Element |
Field components and submit buttons |
errors |
string[] |
Form-level errors to display |
isLoading |
boolean |
Disables all fields while loading |
isProcessing |
boolean |
Controlled override for processing state |
className |
string |
CSS class on the form element |
align |
'left' | 'center' |
Button alignment, defaults to 'left' |
fullWidthButtons |
boolean |
Stretch buttons to full width |
createForm<M>()
Section titled “createForm<M>()”Form and the field components are each generic over the form’s value type (M), and field
components are also generic over their own name (N) — but JSX can’t carry a type parameter from
<Form<M>> down into a sibling field’s own generic inference, so every element is type-checked in
isolation. Spelling out <M, 'name'> on Form and every field works (see InputField below) but
gets repetitive for a component that only ever renders one form. Call createForm<M>() once instead
to bind M for Form and all field components together:
const { Form, InputField, PasswordField } = createForm<LoginValues>();
<Form onSubmit={(values) => values.email}> <InputField name='email' label='Email' required /> <PasswordField name='password' label='Password' required minLength={8} /></Form>;onSubmit’s values, name='bogus', and a self-referencing match are all checked against M,
exactly as if you had written <Form<LoginValues>> and <InputField<LoginValues, 'email'>> at each
call site. The returned components are the real Form/InputField/PasswordField/TextAreaField/
CheckboxField — createForm only fixes M at the type level, it does not wrap or change their
behavior.
Pass a Standard Schema-compatible schema instead of a type argument to infer M from it, the same as
useForm({ schema }):
const { Form, InputField, PasswordField } = createForm({ schema: loginSchema });
<Form onSubmit={(values) => values.email}> <InputField name='email' label='Email' required /> <PasswordField name='password' label='Password' required /></Form>;Fields are typed against the schema’s input (what the DOM gives you); onSubmit receives the
schema’s output, which can differ for a transform/coercion schema. The schema also becomes Form’s
default, so it does not need to be repeated as a schema prop — though an individual <Form schema={other}> call can still override it, same as useForm.
If several field groups need to share one Form/store — a multi-step form, for example — call
createFields<M>() instead to bind just the field components, and wire the shared store up with
useForm/FormContextProvider (see below).
createFields<M>()
Section titled “createFields<M>()”The field-only half of createForm<M>(), for when the fields don’t own their Form:
const { InputField, PasswordField } = createFields<LoginValues>();
<InputField name='email' label='Email' required /><PasswordField name='password' label='Password' required minLength={8} />InputField
Section titled “InputField”Renders a labeled <input type="text">.
<InputField<M, 'email'> name='email' label='Email address' defaultValue='user@example.com' required pattern={/^[^@]+@[^@]+$/}/>| Prop | Type | Description |
|---|---|---|
name |
StringKeyOf<M> |
Field name; must match a key in the form value type |
label |
string |
Visible label text |
defaultValue |
M[N] |
Initial value |
disabled |
boolean |
Disables the input |
readonly |
boolean |
Makes the input read-only |
parse |
(raw: string) => M[N] |
Convert DOM string to typed value |
format |
(val: M[N]) => string |
Convert typed value back to display string |
validator |
CustomValidator<M, N> |
Custom validation function |
required, minLength, maxLength, pattern, min, max, match |
Constraint props | Built-in validation constraints |
All standard HTML input attributes are also accepted.
PasswordField
Section titled “PasswordField”Same props as InputField. Renders <input type="password">.
TextAreaField
Section titled “TextAreaField”Same props as InputField, except type. Renders a <textarea>.
<TextAreaField name='bio' label='Bio' maxLength={500} />CheckboxField
Section titled “CheckboxField”Renders a labeled checkbox. The field value in form state is a boolean.
<CheckboxField name='acceptTerms' label='I accept the terms' required />| Prop | Type | Description |
|---|---|---|
name |
StringKeyOf<M> |
Field name |
label |
string |
Label text |
defaultChecked |
boolean |
Initial checked state |
disabled |
boolean |
Disables the checkbox |
required |
boolean |
Field must be true to be valid |
validator |
CustomValidator<M, N> |
Custom validation function |
SubmitButton
Section titled “SubmitButton”Renders a submit button. It is disabled automatically when the form has validation errors.
<SubmitButton>Log in</SubmitButton>
<SubmitButton name='saveDraft'>Save draft</SubmitButton><SubmitButton name='publish'>Publish</SubmitButton>Named submit buttons select a handler from an object-style onSubmit map, for example
onSubmit={{ saveDraft, publish }}.
| Prop | Type | Description |
|---|---|---|
children |
JSX.Element |
Button label |
isDisabled |
boolean |
Override disabled state |
isFullWidth |
boolean |
Stretch to container width |
name |
string |
Optional field name for multi-button forms |
variant |
'primary' | 'approve' |
Visual variant; approve renders type="button" |
State API
Section titled “State API”form.state is reactive. Access it inside Solid signals, createEffect, or JSX to get fine-grained
updates.
| Property or method | Type | Description |
|---|---|---|
isFormValid |
boolean |
true when no registered field has errors |
haveValuesChanged |
boolean |
true when any field has changed from its initial value |
isLoading |
boolean |
Form is in a loading state |
isProcessing |
boolean |
Async submit handler is in flight |
errors |
string[] |
Form-level errors, including thrown or rejected submit errors |
getFieldValue(name) |
M[N] | undefined |
Current parsed value for a field |
getFieldErrors(name) |
string[] | undefined |
Current errors for a field |
isFieldValid(name) |
boolean | undefined |
false if the field has errors; undefined if not registered |
hasFieldBeenValid(name) |
boolean | undefined |
true once the field has been error-free |
hasFieldBlurred(name) |
boolean | undefined |
true once the user has blurred the field |
hasFieldChanged(name) |
boolean | undefined |
true once the field value has changed |
hasFieldBeenInitialized(name) |
boolean |
true once the field has registered with the store |
Standard Schema Types
Section titled “Standard Schema Types”The package exports StandardSchemaV1, StandardSchemaV1Types, InferStandardSchemaInput,
InferStandardSchemaOutput, StandardSchemaFormValues, and StandardSchemaSubmitValues for custom
schema producers and helpers. StandardSchemaFormValues is the schema input type used by field
state; StandardSchemaSubmitValues is the schema output type passed to onSubmit.