Powerful, type-safe forms for React.
npx @tessl/cli install tessl/npm-tanstack--react-form@1.23.00
# TanStack React Form
1
2
TanStack React Form is a headless, framework-agnostic form state management library for React applications. It provides powerful type-safe form handling with comprehensive validation support, nested field management, and seamless integration with modern React frameworks. The library offers complete control over UI rendering while managing complex form state, validation lifecycles, and field dependencies internally.
3
4
## Package Information
5
6
- **Package Name**: @tanstack/react-form
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Version**: 1.23.7
10
- **Installation**: `npm install @tanstack/react-form`
11
12
## Core Imports
13
14
```typescript
15
import { useForm, useField, useFieldGroup, useStore } from '@tanstack/react-form';
16
import type { FormApi, FieldApi, FormOptions } from '@tanstack/react-form';
17
```
18
19
For CommonJS:
20
21
```javascript
22
const { useForm, useField, useFieldGroup } = require('@tanstack/react-form');
23
```
24
25
Framework-specific imports:
26
27
```typescript
28
// Next.js
29
import { createServerValidate, initialFormState } from '@tanstack/react-form/nextjs';
30
31
// Remix
32
import { createServerValidate, initialFormState } from '@tanstack/react-form/remix';
33
34
// TanStack Start
35
import { createServerValidate, getFormData, initialFormState } from '@tanstack/react-form/start';
36
```
37
38
## Basic Usage
39
40
```typescript
41
import { useForm } from '@tanstack/react-form';
42
43
function MyForm() {
44
const form = useForm({
45
defaultValues: {
46
firstName: '',
47
lastName: '',
48
email: '',
49
},
50
onSubmit: async ({ value }) => {
51
console.log('Form submitted:', value);
52
},
53
});
54
55
return (
56
<form
57
onSubmit={(e) => {
58
e.preventDefault();
59
form.handleSubmit();
60
}}
61
>
62
<form.Field
63
name="firstName"
64
validators={{
65
onChange: ({ value }) =>
66
value.length < 2 ? 'First name must be at least 2 characters' : undefined,
67
}}
68
>
69
{(field) => (
70
<div>
71
<label htmlFor={field.name}>First Name:</label>
72
<input
73
id={field.name}
74
value={field.state.value}
75
onChange={(e) => field.handleChange(e.target.value)}
76
onBlur={field.handleBlur}
77
/>
78
{field.state.meta.errors.length > 0 && (
79
<em>{field.state.meta.errors[0]}</em>
80
)}
81
</div>
82
)}
83
</form.Field>
84
85
<button type="submit" disabled={!form.state.canSubmit}>
86
Submit
87
</button>
88
</form>
89
);
90
}
91
```
92
93
## Architecture
94
95
TanStack React Form is built on several core concepts:
96
97
- **FormApi**: Core form state manager handling validation, submission, and field coordination
98
- **FieldApi**: Individual field state manager with validation and metadata tracking
99
- **FieldGroupApi**: Manages related fields as a logical unit with shared state
100
- **Store Pattern**: Reactive state management using `@tanstack/react-store` for efficient re-renders
101
- **Validation System**: Supports synchronous/asynchronous validators at form and field levels
102
- **Schema Integration**: Compatible with validation libraries via Standard Schema interface
103
- **Framework Adapters**: Server-side validation for Next.js, Remix, and TanStack Start
104
105
## Capabilities
106
107
### Form Management
108
109
Create and manage form state with comprehensive validation and submission handling.
110
111
```typescript { .api }
112
function useForm<
113
TFormData,
114
TOnMount extends undefined | FormValidateOrFn<TFormData> = undefined,
115
TOnChange extends undefined | FormValidateOrFn<TFormData> = undefined,
116
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
117
TOnBlur extends undefined | FormValidateOrFn<TFormData> = undefined,
118
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
119
TOnSubmit extends undefined | FormValidateOrFn<TFormData> = undefined,
120
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
121
TOnDynamic extends undefined | FormValidateOrFn<TFormData> = undefined,
122
TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
123
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
124
TSubmitMeta = never,
125
>(
126
opts?: FormOptions<
127
TFormData,
128
TOnMount,
129
TOnChange,
130
TOnChangeAsync,
131
TOnBlur,
132
TOnBlurAsync,
133
TOnSubmit,
134
TOnSubmitAsync,
135
TOnDynamic,
136
TOnDynamicAsync,
137
TOnServer,
138
TSubmitMeta
139
>,
140
): ReactFormExtendedApi<
141
TFormData,
142
TOnMount,
143
TOnChange,
144
TOnChangeAsync,
145
TOnBlur,
146
TOnBlurAsync,
147
TOnSubmit,
148
TOnSubmitAsync,
149
TOnDynamic,
150
TOnDynamicAsync,
151
TOnServer,
152
TSubmitMeta
153
>;
154
```
155
156
[Form Management](./form-api.md)
157
158
### Field Management
159
160
Manage individual form fields with validation, metadata, and array operations.
161
162
```typescript { .api }
163
function useField<
164
TParentData,
165
TName extends DeepKeys<TParentData>,
166
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
167
TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,
168
TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,
169
TOnChangeAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,
170
TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,
171
TOnBlurAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,
172
TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,
173
TOnSubmitAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,
174
TOnDynamic extends undefined | FieldValidateOrFn<TParentData, TName, TData> = undefined,
175
TOnDynamicAsync extends undefined | FieldAsyncValidateOrFn<TParentData, TName, TData> = undefined,
176
TFormOnMount extends undefined | FormValidateOrFn<TParentData> = undefined,
177
TFormOnChange extends undefined | FormValidateOrFn<TParentData> = undefined,
178
TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,
179
TFormOnBlur extends undefined | FormValidateOrFn<TParentData> = undefined,
180
TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,
181
TFormOnSubmit extends undefined | FormValidateOrFn<TParentData> = undefined,
182
TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,
183
TFormOnDynamic extends undefined | FormValidateOrFn<TParentData> = undefined,
184
TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,
185
TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData> = undefined,
186
TParentSubmitMeta = never,
187
>(
188
opts: UseFieldOptions<
189
TParentData,
190
TName,
191
TData,
192
TOnMount,
193
TOnChange,
194
TOnChangeAsync,
195
TOnBlur,
196
TOnBlurAsync,
197
TOnSubmit,
198
TOnSubmitAsync,
199
TOnDynamic,
200
TOnDynamicAsync,
201
TFormOnMount,
202
TFormOnChange,
203
TFormOnChangeAsync,
204
TFormOnBlur,
205
TFormOnBlurAsync,
206
TFormOnSubmit,
207
TFormOnSubmitAsync,
208
TFormOnDynamic,
209
TFormOnDynamicAsync,
210
TFormOnServer,
211
TParentSubmitMeta
212
>,
213
): FieldApi<
214
TParentData,
215
TName,
216
TData,
217
TOnMount,
218
TOnChange,
219
TOnChangeAsync,
220
TOnBlur,
221
TOnBlurAsync,
222
TOnSubmit,
223
TOnSubmitAsync,
224
TOnDynamic,
225
TOnDynamicAsync,
226
TFormOnMount,
227
TFormOnChange,
228
TFormOnChangeAsync,
229
TFormOnBlur,
230
TFormOnBlurAsync,
231
TFormOnSubmit,
232
TFormOnSubmitAsync,
233
TFormOnDynamic,
234
TFormOnDynamicAsync,
235
TFormOnServer,
236
TParentSubmitMeta
237
>;
238
```
239
240
[Field Management](./field-api.md)
241
242
### React Hooks
243
244
React-specific hooks for form and field state management with reactivity.
245
246
```typescript { .api }
247
// Store subscription hook for reactive updates
248
function useStore<TState, TSelected = TState>(
249
store: Store<TState>,
250
selector?: (state: TState) => TSelected,
251
): TSelected;
252
253
// Form transformation hook
254
function useTransform(
255
fn: (formBase: AnyFormApi) => AnyFormApi,
256
deps: unknown[],
257
): FormTransform<any, any, any, any, any, any, any, any, any, any, any, any>;
258
259
// Field group management hook
260
function useFieldGroup<
261
TFormData,
262
TFieldGroupData,
263
TFields extends DeepKeysOfType<TFormData, TFieldGroupData | null | undefined> | FieldsMap<TFormData, TFieldGroupData>,
264
TOnMount extends undefined | FormValidateOrFn<TFormData> = undefined,
265
TOnChange extends undefined | FormValidateOrFn<TFormData> = undefined,
266
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
267
TOnBlur extends undefined | FormValidateOrFn<TFormData> = undefined,
268
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
269
TOnSubmit extends undefined | FormValidateOrFn<TFormData> = undefined,
270
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
271
TOnDynamic extends undefined | FormValidateOrFn<TFormData> = undefined,
272
TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
273
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
274
TComponents extends Record<string, ComponentType<any>> = {},
275
TFormComponents extends Record<string, ComponentType<any>> = {},
276
TSubmitMeta = never,
277
>(opts: FieldGroupOptions<
278
TFormData,
279
TFieldGroupData,
280
TFields,
281
TOnMount,
282
TOnChange,
283
TOnChangeAsync,
284
TOnBlur,
285
TOnBlurAsync,
286
TOnSubmit,
287
TOnSubmitAsync,
288
TOnDynamic,
289
TOnDynamicAsync,
290
TOnServer,
291
TSubmitMeta,
292
TComponents,
293
TFormComponents
294
>): AppFieldExtendedReactFieldGroupApi<
295
TFormData,
296
TFieldGroupData,
297
TFields,
298
TOnMount,
299
TOnChange,
300
TOnChangeAsync,
301
TOnBlur,
302
TOnBlurAsync,
303
TOnSubmit,
304
TOnSubmitAsync,
305
TOnDynamic,
306
TOnDynamicAsync,
307
TOnServer,
308
TSubmitMeta,
309
TComponents,
310
TFormComponents
311
>;
312
```
313
314
[React Hooks](./hooks.md)
315
316
### Validation System
317
318
Comprehensive validation with sync/async validators, schema integration, and error handling.
319
320
```typescript { .api }
321
// Standard Schema validator interface
322
interface StandardSchemaV1<Input = unknown, Output = Input> {
323
readonly '~standard': StandardSchemaV1.Props<Input, Output>;
324
}
325
326
namespace StandardSchemaV1 {
327
interface Props<Input, Output> {
328
readonly version: 1;
329
readonly vendor: string;
330
readonly validate: (
331
value: unknown,
332
) => Result<Output> | Promise<Result<Output>>;
333
}
334
335
interface Result<Output> {
336
readonly value?: Output;
337
readonly issues?: ReadonlyArray<StandardSchemaV1Issue>;
338
}
339
}
340
341
// Type guard for Standard Schema validators
342
function isStandardSchemaValidator(
343
validator: unknown,
344
): validator is StandardSchemaV1;
345
346
// Standard Schema validation helpers
347
const standardSchemaValidators: {
348
validate<TInput, TOutput>(
349
value: TInput,
350
schema: StandardSchemaV1<TInput, TOutput>,
351
): ValidationError | undefined;
352
353
validateAsync<TInput, TOutput>(
354
value: TInput,
355
schema: StandardSchemaV1<TInput, TOutput>,
356
): Promise<ValidationError | undefined>;
357
};
358
```
359
360
[Validation System](./validation.md)
361
362
### Advanced Form Patterns
363
364
Create custom form hooks with component injection and higher-order components.
365
366
```typescript { .api }
367
function createFormHook<
368
const TComponents extends Record<string, ComponentType<any>>,
369
const TFormComponents extends Record<string, ComponentType<any>>,
370
>({
371
fieldComponents,
372
fieldContext,
373
formContext,
374
formComponents,
375
}: CreateFormHookProps<TComponents, TFormComponents>): {
376
useAppForm: <TFormData, ...>(
377
props: FormOptions<TFormData, ...>,
378
) => AppFieldExtendedReactFormApi<TFormData, ..., TComponents, TFormComponents>;
379
380
withForm: <TFormData, ...>(
381
props: WithFormProps<TFormData, ..., TComponents, TFormComponents>,
382
) => (props: any) => JSX.Element;
383
384
withFieldGroup: <TFieldGroupData, TSubmitMeta, TRenderProps>(
385
props: WithFieldGroupProps<TFieldGroupData, TComponents, TFormComponents, TSubmitMeta, TRenderProps>,
386
) => (props: any) => JSX.Element;
387
};
388
389
function createFormHookContexts(): {
390
fieldContext: Context<AnyFieldApi>;
391
useFieldContext: <TData>() => FieldApi<any, string, TData, ...>;
392
useFormContext: () => ReactFormExtendedApi<Record<string, never>, ...>;
393
formContext: Context<AnyFormApi>;
394
};
395
```
396
397
[Advanced Form Patterns](./advanced.md)
398
399
### Framework Integrations
400
401
Server-side validation utilities for Next.js, Remix, and TanStack Start.
402
403
```typescript { .api }
404
// Next.js / Remix
405
function createServerValidate<
406
TFormData,
407
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
408
>(
409
defaultOpts: CreateServerValidateOptions<TFormData, TOnServer>,
410
): (
411
formData: FormData,
412
info?: { resolve?: (fieldName: string) => string | File },
413
) => Promise<TFormData>;
414
415
const initialFormState: ServerFormState<any, undefined>;
416
417
class ServerValidateError<TFormData, TOnServer> extends Error {
418
formState: ServerFormState<TFormData, TOnServer>;
419
}
420
421
// TanStack Start (additional)
422
function getFormData(): Promise<ServerFormState<any, undefined> | typeof initialFormState>;
423
```
424
425
[Framework Integrations](./framework-integrations.md)
426
427
## Types
428
429
### External Type References
430
431
Types from re-exported dependencies:
432
433
```typescript { .api }
434
// From @tanstack/react-store
435
interface Store<TState> {
436
state: TState;
437
subscribe: (listener: () => void) => () => void;
438
setState: (updater: (state: TState) => TState) => void;
439
}
440
441
// From React
442
type ComponentType<P = {}> = React.ComponentClass<P> | React.FunctionComponent<P>;
443
type PropsWithChildren<P = unknown> = P & { children?: ReactNode };
444
interface ReactElement {
445
type: string | ComponentType<any>;
446
props: any;
447
key: string | number | null;
448
}
449
type ReactNode = ReactElement | string | number | boolean | null | undefined;
450
interface Context<T> {
451
Provider: ComponentType<{ value: T }>;
452
Consumer: ComponentType<{ children: (value: T) => ReactNode }>;
453
}
454
455
// JSX namespace for TypeScript
456
namespace JSX {
457
type Element = ReactElement;
458
}
459
```
460
461
### Core Type Utilities
462
463
```typescript { .api }
464
/**
465
* Deep key navigation types for accessing nested properties with type safety
466
*/
467
468
/**
469
* Extracts all possible deep keys from a type as dot-notation strings
470
* Example: For type { user: { name: string, age: number } }
471
* Results in: "user" | "user.name" | "user.age"
472
*/
473
type DeepKeys<T> = unknown extends T ? string : DeepKeysAndValues<T>['key'];
474
475
/**
476
* Gets the type of a value at a specific deep key path
477
* Example: DeepValue<{ user: { name: string } }, "user.name"> = string
478
*/
479
type DeepValue<TValue, TAccessor> = unknown extends TValue
480
? TValue
481
: TAccessor extends DeepKeys<TValue>
482
? DeepRecord<TValue>[TAccessor]
483
: never;
484
485
/**
486
* Filters deep keys to only those with values matching a specific type
487
* Example: DeepKeysOfType<{ a: string, b: number, c: string }, string> = "a" | "c"
488
*/
489
type DeepKeysOfType<TData, TValue> = Extract<
490
DeepKeysAndValues<TData>,
491
AnyDeepKeyAndValue<string, TValue>
492
>['key'];
493
494
/**
495
* Maps deep keys of TFormData to shallow keys of TFieldGroupData
496
* Used for field groups to map form fields to group data structure
497
* Since using template strings as keys is impractical, it relies on shallow keys only
498
* Example: FieldsMap<{ user: { name: string } }, { name: string }> creates a mapping
499
* from deep form paths to shallow group keys
500
*/
501
type FieldsMap<TFormData, TFieldGroupData> = {
502
[K in keyof TFieldGroupData]: DeepKeysOfType<
503
TFormData,
504
TFieldGroupData[K] | null | undefined
505
>;
506
};
507
508
/**
509
* Updater types for functional state updates
510
* Accepts either a new value or a function that receives the current value
511
*/
512
type Updater<TInput, TOutput = TInput> = TOutput | UpdaterFn<TInput, TOutput>;
513
514
/** Function type for updating values */
515
type UpdaterFn<TInput, TOutput = TInput> = (input: TInput) => TOutput;
516
517
/**
518
* Validation types
519
*/
520
521
/** Type representing a validation error (can be any value - string, object, etc.) */
522
type ValidationError = unknown;
523
524
/** Events that can trigger validation */
525
type ValidationCause = 'change' | 'blur' | 'submit' | 'mount' | 'server' | 'dynamic';
526
527
/**
528
* Source of validation - indicates whether a validation error originated from
529
* form-level validators or field-level validators. Used in error tracking and
530
* error source maps to distinguish between different validation sources.
531
*/
532
type ValidationSource = 'form' | 'field';
533
534
/**
535
* Options for controlling field operations
536
* Used to fine-tune behavior when updating field values or metadata
537
*/
538
interface UpdateMetaOptions {
539
/** Skip metadata update (touched, dirty, etc.) */
540
dontUpdateMeta?: boolean;
541
/** Skip validation after update */
542
dontValidate?: boolean;
543
/** Skip running change/blur listeners */
544
dontRunListeners?: boolean;
545
}
546
```
547
548
### Form and Field State
549
550
```typescript { .api }
551
interface FormState<TFormData, ...> {
552
values: TFormData;
553
errors: ValidationError[];
554
errorMap: FormValidationErrorMap<TFormData, ...>;
555
fieldMeta: Record<DeepKeys<TFormData>, FieldMeta<any, any, any, ...>>;
556
canSubmit: boolean;
557
isSubmitting: boolean;
558
isTouched: boolean;
559
isPristine: boolean;
560
isDirty: boolean;
561
isValid: boolean;
562
isValidating: boolean;
563
submissionAttempts: number;
564
validationMetaMap: Record<ValidationErrorMapKeys, ValidationMeta>;
565
}
566
567
interface FieldState<TData> {
568
value: TData;
569
meta: FieldMeta<TData, any, any, ...>;
570
}
571
572
interface FieldMeta<TData, ...> {
573
isTouched: boolean;
574
isBlurred: boolean;
575
isPristine: boolean;
576
isDirty: boolean;
577
errors: ValidationError[];
578
errorMap: ValidationErrorMap;
579
errorSourceMap: ValidationErrorMapSource;
580
isValidating: boolean;
581
isValid: boolean;
582
isDefaultValue: boolean;
583
}
584
```
585