Form
A form model for the forms your product is actually built around.
Form connects deeply typed values, validation events, async checks, derived submit state, and your own field components—without hiding the form model behind a UI kit.
profile.emailvalidEmail shape is valid.
company.planvalidmembers[2].rolevalidRole is available.
live form state
- value type
- OnboardingForm
- dirty
- 0 fields
- validating
- 0 async
- can submit
- true
Composition
Build your form system once. Keep every form specific.
Create the field components and defaults your team agrees on, then compose product-specific forms without giving up inference or markup control.
useAppForm()
Defaults, validators, submit behavior
<form.AppField>
Your inputs, labels, hints, errors
withForm()
Typed composition for each workflow
Validation orchestration
Run each rule at the speed of the user.
Validation is not one callback. Put each rule at the event where it helps, debounce expensive checks, and expose pending state to the exact surface that needs it.
onChangeShape the value while the user types
Required fields, formatting
onBlurWait until the user leaves the field
Longer rules, calmer feedback
onChangeAsyncDebounce work that crosses the network
Username and coupon checks
onSubmitGuard the final business invariant
Cross-field and server rules
Granular subscriptions
Large forms update in small pieces.
A price preview can listen to the plan. A submit button can listen to canSubmit. Field feedback can listen to its own metadata. The rest of the form stays quiet.
field
1 render
summary
0 renders
submit
1 render
<form.Subscribe>
selector={(state) => state.canSubmit}
{canSubmit => (
<button disabled={!canSubmit}>Save</button>
)}
</form.Subscribe>form.state.canSubmit
changed
SaveButton
rendered