TanStack Form
Overview
TanStack Form is a headless form state manager, not a UI component library. You provide your own inputs and handle their events; TanStack Form manages validation, state, and submission logic.
When to use: Complex multi-step forms, reusable form patterns, dynamic field arrays, cross-field validation, async server validation, forms requiring fine-grained performance optimization.
When NOT to use: Simple forms with native HTML validation (use plain form elements), server-only validation (use Server Actions), purely static forms with no validation.
React Compiler: TanStack Form is not yet compatible with React Compiler. Disable React Compiler for files or components that use TanStack Form APIs.
Quick Reference
| Pattern |
API |
Key Points |
| Basic form |
useForm({ defaultValues, onSubmit }) |
Form instance with Field component |
| Field |
form.Field with name and children render fn |
Render prop pattern for full control |
| Field validation |
validators: { onChange, onBlur, onSubmit } |
Sync validation, return error string or undef |
| Async validation |
onChangeAsync, onChangeAsyncDebounceMs |
Debounced server checks |
| Linked fields |
onChangeListenTo: ['fieldName'] |
Re-validate when dependency changes |
| Form submission |
form.handleSubmit() |
Validates and calls onSubmit if valid |
| Form state |
form.state.values, isSubmitting, isValid |
Access form-level state |
| Field state |
field.state.value, meta.errors, meta.isTouched |
Access field-level state |
| Array fields |
mode="array", pushValue, removeValue |
Dynamic lists with helpers |
| Standard Schema |
Pass Zod/Valibot/ArkType/Yup schema directly |
Native support, no adapter needed |
| Form composition |
createFormHook({ fieldComponents }) |
Reusable fields with context |
| Break up large forms |
withForm({ defaultValues, render }) |
HOC for form sections with type safety |
| Reusable field groups |
withFieldGroup({ defaultValues, render }) |
Grouped fields with shared validation logic |
| Subscribe to state |
form.Subscribe with selector |
Efficient re-render control |
| Field error display |
meta.isTouched && meta.errors.length |
Show errors after user interaction |
| Form-level validation |
validators.onSubmit returning { fields } |
Set errors on specific fields from form level |
| Reset form |
form.reset() |
Reset to defaultValues |
Common Mistakes
| Mistake |
Correct Pattern |
Using e.target.value directly |
Use field.handleChange(value) for proper state management |
Missing onBlur={field.handleBlur} |
Always add for validation timing and touched state |
| Showing errors immediately |
Check field.state.meta.isTouched && errors.length |
| Not specifying debounce for async validation |
Set onChangeAsyncDebounceMs to avoid excessive server requests |
Using listeners for validation |
Use onChangeListenTo in validators for re-validation |
| Validating only on submit |
Add onChange or onBlur validators for better UX |
| Not handling form submission properly |
Prevent default and call form.handleSubmit() |
| Creating QueryClient-style instances |
Use useForm hook directly in components |
| Inline validator functions |
Extract to stable references or wrap in useCallback |
| Missing field names in array fields |
Use template syntax hobbies[${index}].name for nested fields |
| Not awaiting async validators |
Return Promise directly, Form handles awaiting |
Checking isValidating before submission |
Use canSubmit state selector instead |
Delegation
- Form pattern discovery: Use
Explore agent for finding existing form implementations
- Validation schema design: Use
Task agent for complex cross-field validation logic
- Code review: Delegate to
code-reviewer agent for form validation coverage
If the shadcn-ui skill is available, delegate component styling and composition to it. Otherwise, recommend: npx skills add oakoss/agent-skills --skill shadcn-ui
If the tanstack-query skill is available, delegate cache management and mutation patterns to it.
If the tanstack-start skill is available, delegate server functions and server-side form submission to it.
If the tanstack-router skill is available, delegate post-submission navigation and route patterns to it.
If the tanstack-devtools skill is available, delegate form state debugging to it.
References
- Basic patterns and form setup
- Field validation (sync, async, linked fields)
- Schema validation (Zod, Valibot, ArkType, Yup)
- Array fields and dynamic lists
- Form composition and reusable fields
- Advanced patterns (multi-step forms, file uploads)
- Server integration (mutations, cache coordination, server functions)
- React Aria integration (TextField, Select, Switch, Checkbox, RadioGroup)
- shadcn/ui integration (Field layout, Input, Select, Switch, Checkbox, RadioGroup)
1---
2name: tanstack-form
3description: |
4 TanStack Form v1 headless form state management for React. Covers field validation (sync/async, debouncing), form submission, array fields, linked fields, form composition patterns, and Standard Schema integration (Zod, Valibot, ArkType, Yup).
5
6 Use when building forms with complex validation, implementing reusable form components, handling dynamic field lists, managing form state, or integrating validation libraries.
7license: MIT
8metadata:
9 author: oakoss
10 version: '1.1'
11 source: 'https://tanstack.com/form/latest/docs'
12user-invocable: false
13---
14
15# TanStack Form
16
17## Overview
18
19TanStack Form is a **headless form state manager**, not a UI component library. You provide your own inputs and handle their events; TanStack Form manages validation, state, and submission logic.
20
21**When to use:** Complex multi-step forms, reusable form patterns, dynamic field arrays, cross-field validation, async server validation, forms requiring fine-grained performance optimization.
22
23**When NOT to use:** Simple forms with native HTML validation (use plain form elements), server-only validation (use Server Actions), purely static forms with no validation.
24
25**React Compiler:** TanStack Form is not yet compatible with React Compiler. Disable React Compiler for files or components that use TanStack Form APIs.
26
27## Quick Reference
28
29| Pattern | API | Key Points |
30| --------------------- | ---------------------------------------------------- | --------------------------------------------- |
31| Basic form | `useForm({ defaultValues, onSubmit })` | Form instance with Field component |
32| Field | `form.Field` with `name` and `children` render fn | Render prop pattern for full control |
33| Field validation | `validators: { onChange, onBlur, onSubmit }` | Sync validation, return error string or undef |
34| Async validation | `onChangeAsync`, `onChangeAsyncDebounceMs` | Debounced server checks |
35| Linked fields | `onChangeListenTo: ['fieldName']` | Re-validate when dependency changes |
36| Form submission | `form.handleSubmit()` | Validates and calls onSubmit if valid |
37| Form state | `form.state.values`, `isSubmitting`, `isValid` | Access form-level state |
38| Field state | `field.state.value`, `meta.errors`, `meta.isTouched` | Access field-level state |
39| Array fields | `mode="array"`, `pushValue`, `removeValue` | Dynamic lists with helpers |
40| Standard Schema | Pass Zod/Valibot/ArkType/Yup schema directly | Native support, no adapter needed |
41| Form composition | `createFormHook({ fieldComponents })` | Reusable fields with context |
42| Break up large forms | `withForm({ defaultValues, render })` | HOC for form sections with type safety |
43| Reusable field groups | `withFieldGroup({ defaultValues, render })` | Grouped fields with shared validation logic |
44| Subscribe to state | `form.Subscribe` with `selector` | Efficient re-render control |
45| Field error display | `meta.isTouched && meta.errors.length` | Show errors after user interaction |
46| Form-level validation | `validators.onSubmit` returning `{ fields }` | Set errors on specific fields from form level |
47| Reset form | `form.reset()` | Reset to defaultValues |
48
49## Common Mistakes
50
51| Mistake | Correct Pattern |
52| -------------------------------------------- | ---------------------------------------------------------------- |
53| Using `e.target.value` directly | Use `field.handleChange(value)` for proper state management |
54| Missing `onBlur={field.handleBlur}` | Always add for validation timing and touched state |
55| Showing errors immediately | Check `field.state.meta.isTouched && errors.length` |
56| Not specifying debounce for async validation | Set `onChangeAsyncDebounceMs` to avoid excessive server requests |
57| Using `listeners` for validation | Use `onChangeListenTo` in validators for re-validation |
58| Validating only on submit | Add `onChange` or `onBlur` validators for better UX |
59| Not handling form submission properly | Prevent default and call `form.handleSubmit()` |
60| Creating QueryClient-style instances | Use `useForm` hook directly in components |
61| Inline validator functions | Extract to stable references or wrap in useCallback |
62| Missing field names in array fields | Use template syntax `hobbies[${index}].name` for nested fields |
63| Not awaiting async validators | Return Promise directly, Form handles awaiting |
64| Checking `isValidating` before submission | Use `canSubmit` state selector instead |
65
66## Delegation
67
68- **Form pattern discovery**: Use `Explore` agent for finding existing form implementations
69- **Validation schema design**: Use `Task` agent for complex cross-field validation logic
70- **Code review**: Delegate to `code-reviewer` agent for form validation coverage
71
72> If the `shadcn-ui` skill is available, delegate component styling and composition to it. Otherwise, recommend: `npx skills add oakoss/agent-skills --skill shadcn-ui`
73>
74> If the `tanstack-query` skill is available, delegate cache management and mutation patterns to it.
75> If the `tanstack-start` skill is available, delegate server functions and server-side form submission to it.
76> If the `tanstack-router` skill is available, delegate post-submission navigation and route patterns to it.
77> If the `tanstack-devtools` skill is available, delegate form state debugging to it.
78
79## References
80
81- [Basic patterns and form setup](references/basic-patterns.md)
82- [Field validation (sync, async, linked fields)](references/validation.md)
83- [Schema validation (Zod, Valibot, ArkType, Yup)](references/schema-validation.md)
84- [Array fields and dynamic lists](references/array-fields.md)
85- [Form composition and reusable fields](references/form-composition.md)
86- [Advanced patterns (multi-step forms, file uploads)](references/advanced-patterns.md)
87- [Server integration (mutations, cache coordination, server functions)](references/server-integration.md)
88- [React Aria integration (TextField, Select, Switch, Checkbox, RadioGroup)](references/react-aria-integration.md)
89- [shadcn/ui integration (Field layout, Input, Select, Switch, Checkbox, RadioGroup)](references/shadcn-integration.md)