Advanced
Practical guides for building accessible, reusable, and performant forms
Each guide solves one problem end to end: when you need it, a complete TypeScript example, how it works, and the mistakes to avoid. For a learning path, start with Guides. For function signatures and options, see the API reference.
Find a pattern for your task
| I want to… | Start here |
|---|---|
| Edit an existing record without losing user changes | Editing saved data |
| Display API validation errors and allow retries | Handling server errors |
| Collect data across several steps | Multi-step forms |
| Submit with React 19 and Next.js | Server Actions |
| Show fields based on another input | Conditional fields |
| Avoid re-rendering a large form on every keystroke | Isolating form subscriptions |
| Make labels, errors, and focus work together | Accessibility |
| Share form methods with nested components | Connect form |
| Test validation and submission | Testing forms |
| Use a component library or schema validator | Integrations |
Data and submission
- Editing saved data: load a record, keep the user's edits, and save what changed.
- Handling server errors: map API validation errors onto fields and report failed requests.
- Multi-step forms: collect one typed payload across steps, with saved drafts and server validation.
- Server Actions: validate on the client, then submit with
useActionState. - Transform and parse: convert between input strings and the types you store.
Dynamic fields
- Conditional fields: show, hide, and validate fields based on other answers.
- Controlled and uncontrolled inputs: mix native inputs with controlled UI components.
- Virtualized lists: keep values and validation for rows that are not mounted.
- Opaque types: treat Dayjs, Decimal, and other class values as single fields in TypeScript.
Reusable components
- Smart form component: a
Formcomponent that wires registration into its children. - Connect form: reach form methods from deeply nested inputs.
- Error messages: render validation messages consistently.
- Custom resolver: write a resolver for any validation library or hand-written rules.
Performance
- Isolating form subscriptions: re-render only the components that display a value.
- FormProvider performance: keep context consumers from re-rendering on every change.
Quality
- Accessibility: labels, error announcements, and focus management.
- Testing forms: test validation and submission the way users interact with the form.
Upgrading an existing project? Follow the Migrate to v8 guide.