Powerful, type-safe forms for React.
The FormApi class provides comprehensive form state management including validation, submission handling, field coordination, and lifecycle events. It serves as the core of TanStack React Form's state management system.
Core form management class with methods for validation, submission, and field manipulation.
class FormApi<
TFormData,
TOnMount extends undefined | FormValidateOrFn<TFormData> = undefined,
TOnChange extends undefined | FormValidateOrFn<TFormData> = undefined,
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
TOnBlur extends undefined | FormValidateOrFn<TFormData> = undefined,
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
TOnSubmit extends undefined | FormValidateOrFn<TFormData> = undefined,
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
TOnDynamic extends undefined | FormValidateOrFn<TFormData> = undefined,
TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData> = undefined,
TSubmitMeta = never,
> {
/** Store instance for reactive state management */
store: Store<FormState<TFormData, ...>>;
/** Current form state */
state: FormState<TFormData, ...>;
/** Form configuration options */
options: FormOptions<TFormData, ...>;
/** Record of field information for each field in the form */
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>>;
constructor(opts?: FormOptions<TFormData, ...>);
/**
* Mounts the form and runs mount validation
* Call this when the form component mounts to initialize validation and event listeners
* @returns Cleanup function to unmount the form and remove listeners
*/
mount(): () => void;
/**
* Updates form options with new configuration
* Updates values and state if defaultValues or defaultState changed and form is pristine
* Re-evaluates transform function if transform deps changed
* @param options - Form options to update
*/
update(
options?: FormOptions<TFormData, ...>,
): void;
/**
* Resets the form to its initial state
* @param values - Optional new values to reset to (defaults to defaultValues)
* @param opts - Options for reset behavior
*/
reset(values?: TFormData, opts?: { keepDefaultValues?: boolean }): void;
/**
* Validates all fields in the form
* @param cause - Reason for validation (e.g., 'change', 'blur', 'submit')
* @returns Promise that resolves to array of validation errors
*/
validateAllFields(
cause: ValidationCause,
): Promise<ValidationError[]>;
/**
* Validates array field children starting from a specific index
* @param field - Field path to validate
* @param index - Starting index for validation
* @param cause - Reason for validation
* @returns Promise that resolves to array of validation errors
*/
validateArrayFieldsStartingFrom<TField extends DeepKeys<TFormData>>(
field: TField,
index: number,
cause: ValidationCause,
): Promise<ValidationError[]>;
/**
* Validates a specific field
* @param field - Field path to validate
* @param cause - Reason for validation
* @returns Promise that resolves to array of validation errors
*/
validateField<TField extends DeepKeys<TFormData>>(
field: TField,
cause: ValidationCause,
): Promise<ValidationError[]>;
/**
* Handles form submission with optional metadata
* @param submitMeta - Optional metadata to pass to submit handlers
* @returns Promise that resolves when submission completes
*/
handleSubmit(submitMeta?: TSubmitMeta): Promise<void>;
/**
* Gets the current value of a field
* @param field - Field path
* @returns Current field value
*/
getFieldValue<TField extends DeepKeys<TFormData>>(
field: TField,
): DeepValue<TFormData, TField>;
/**
* Gets the metadata for a field
* @param field - Field path
* @returns Field metadata
*/
getFieldMeta<TField extends DeepKeys<TFormData>>(
field: TField,
): FieldMeta<DeepValue<TFormData, TField>, any, any, ...> | undefined;
/**
* Sets the metadata for a field
* @param field - Field path
* @param updater - Function or value to update metadata
*/
setFieldMeta<TField extends DeepKeys<TFormData>>(
field: TField,
updater: Updater<FieldMeta<DeepValue<TFormData, TField>, any, any, ...>>,
): void;
/**
* Sets the value of a field
* @param field - Field path
* @param updater - Function or value to set
* @param opts - Options to control metadata updates and validation
*/
setFieldValue<TField extends DeepKeys<TFormData>>(
field: TField,
updater: Updater<DeepValue<TFormData, TField>>,
opts?: UpdateMetaOptions,
): void;
/**
* Deletes a field from the form
* @param field - Field path to delete
*/
deleteField<TField extends DeepKeys<TFormData>>(
field: TField,
): void;
/**
* Pushes a value to an array field
* @param field - Field path (must be an array)
* @param value - Value to push
* @param opts - Options to control metadata updates and validation
*/
pushFieldValue<TField extends DeepKeys<TFormData>>(
field: TField,
value: DeepValue<TFormData, TField> extends Array<infer U> ? U : never,
opts?: UpdateMetaOptions,
): void;
/**
* Inserts a value at a specific index in an array field
* @param field - Field path (must be an array)
* @param index - Index at which to insert
* @param value - Value to insert
* @param opts - Options to control metadata updates and validation
*/
insertFieldValue<TField extends DeepKeys<TFormData>>(
field: TField,
index: number,
value: DeepValue<TFormData, TField> extends Array<infer U> ? U : never,
opts?: UpdateMetaOptions,
): Promise<void>;
/**
* Replaces a value at a specific index in an array field
* @param field - Field path (must be an array)
* @param index - Index to replace
* @param value - New value
* @param opts - Options to control metadata updates and validation
*/
replaceFieldValue<TField extends DeepKeys<TFormData>>(
field: TField,
index: number,
value: DeepValue<TFormData, TField> extends Array<infer U> ? U : never,
opts?: UpdateMetaOptions,
): Promise<void>;
/**
* Removes a value at a specific index from an array field
* @param field - Field path (must be an array)
* @param index - Index to remove
* @param opts - Options to control metadata updates and validation
*/
removeFieldValue<TField extends DeepKeys<TFormData>>(
field: TField,
index: number,
opts?: UpdateMetaOptions,
): Promise<void>;
/**
* Swaps two values in an array field
* @param field - Field path (must be an array)
* @param index1 - First index
* @param index2 - Second index
* @param opts - Options to control metadata updates and validation
*/
swapFieldValues<TField extends DeepKeys<TFormData>>(
field: TField,
index1: number,
index2: number,
opts?: UpdateMetaOptions,
): void;
/**
* Moves a value from one index to another in an array field
* @param field - Field path (must be an array)
* @param index1 - Source index
* @param index2 - Destination index
* @param opts - Options to control metadata updates and validation
*/
moveFieldValues<TField extends DeepKeys<TFormData>>(
field: TField,
index1: number,
index2: number,
opts?: UpdateMetaOptions,
): void;
/**
* Clears all values from an array field
* @param field - Field path (must be an array)
* @param opts - Options to control metadata updates and validation
*/
clearFieldValues<TField extends DeepKeys<TFormData>>(
field: TField,
opts?: UpdateMetaOptions,
): void;
/**
* Resets a field to its default value
* @param field - Field path to reset
*/
resetField<TField extends DeepKeys<TFormData>>(
field: TField,
): void;
/**
* Gets the field info of the specified field including instance and validation metadata
* @param field - Field path to get info for
* @returns FieldInfo containing field instance and validation metadata
*/
getFieldInfo<TField extends DeepKeys<TFormData>>(
field: TField,
): FieldInfo<TFormData>;
/**
* Updates the form's errorMap directly
* Useful for setting server-side validation errors
* @param errorMap - New error map to set
*/
setErrorMap(
errorMap: FormValidationErrorMap<
TFormData,
UnwrapFormValidateOrFn<TOnMount>,
UnwrapFormValidateOrFn<TOnChange>,
UnwrapFormAsyncValidateOrFn<TOnChangeAsync>,
UnwrapFormValidateOrFn<TOnBlur>,
UnwrapFormAsyncValidateOrFn<TOnBlurAsync>,
UnwrapFormValidateOrFn<TOnSubmit>,
UnwrapFormAsyncValidateOrFn<TOnSubmitAsync>,
UnwrapFormValidateOrFn<TOnDynamic>,
UnwrapFormAsyncValidateOrFn<TOnDynamicAsync>,
UnwrapFormAsyncValidateOrFn<TOnServer>
>,
): void;
/**
* Returns both form-level and field-level errors
* Provides a complete view of all validation errors in the form
* @returns Object containing form errors and field errors
*/
getAllErrors(): {
form: {
errors: Array<
| UnwrapFormValidateOrFn<TOnMount>
| UnwrapFormAsyncValidateOrFn<TOnChangeAsync>
| UnwrapFormValidateOrFn<TOnChange>
| UnwrapFormValidateOrFn<TOnBlur>
| UnwrapFormAsyncValidateOrFn<TOnBlurAsync>
| UnwrapFormValidateOrFn<TOnSubmit>
| UnwrapFormAsyncValidateOrFn<TOnSubmitAsync>
| UnwrapFormValidateOrFn<TOnDynamic>
| UnwrapFormAsyncValidateOrFn<TOnDynamicAsync>
| UnwrapFormAsyncValidateOrFn<TOnServer>
>;
errorMap: ValidationErrorMap<
| UnwrapFormValidateOrFn<TOnMount>
| UnwrapFormAsyncValidateOrFn<TOnChangeAsync>
| UnwrapFormValidateOrFn<TOnChange>
| UnwrapFormValidateOrFn<TOnBlur>
| UnwrapFormAsyncValidateOrFn<TOnBlurAsync>
| UnwrapFormValidateOrFn<TOnSubmit>
| UnwrapFormAsyncValidateOrFn<TOnSubmitAsync>
| UnwrapFormValidateOrFn<TOnDynamic>
| UnwrapFormAsyncValidateOrFn<TOnDynamicAsync>
| UnwrapFormAsyncValidateOrFn<TOnServer>
>;
};
fields: Record<
DeepKeys<TFormData>,
{ errors: ValidationError[]; errorMap: ValidationErrorMap }
>;
};
/**
* Parses form values with a Standard Schema without setting internal errors
* Useful for one-off validation checks without affecting form state
* @param schema - The Standard Schema to validate against
* @returns Validation error if any, undefined if valid
*/
parseValuesWithSchema(
schema: StandardSchemaV1<TFormData, unknown>,
): ValidationError | undefined;
/**
* Async version of parseValuesWithSchema
* Parses form values with a Standard Schema without setting internal errors
* @param schema - The Standard Schema to validate against
* @returns Promise resolving to validation error if any, undefined if valid
*/
parseValuesWithSchemaAsync(
schema: StandardSchemaV1<TFormData, unknown>,
): Promise<ValidationError | undefined>;
/**
* Gets the unique form identifier
* Useful for debugging and devtools integration
*/
get formId(): string;
}React-specific extension of FormApi with Field component and Subscribe function.
type ReactFormExtendedApi<
TFormData,
TOnMount extends undefined | FormValidateOrFn<TFormData>,
TOnChange extends undefined | FormValidateOrFn<TFormData>,
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
TSubmitMeta,
> = FormApi<
TFormData,
TOnMount,
TOnChange,
TOnChangeAsync,
TOnBlur,
TOnBlurAsync,
TOnSubmit,
TOnSubmitAsync,
TOnDynamic,
TOnDynamicAsync,
TOnServer,
TSubmitMeta
> & {
/**
* A React component to render form fields
* Automatically bound to this form instance
*/
Field: FieldComponent<
TFormData,
TOnMount,
TOnChange,
TOnChangeAsync,
TOnBlur,
TOnBlurAsync,
TOnSubmit,
TOnSubmitAsync,
TOnDynamic,
TOnDynamicAsync,
TOnServer,
TSubmitMeta
>;
/**
* A Subscribe function to listen and react to form state changes
* Useful for side effects or conditional rendering based on state
*/
Subscribe: <TSelected = FormState<TFormData, ...>>(props: {
selector?: (state: FormState<TFormData, ...>) => TSelected;
children: ((state: TSelected) => ReactNode) | ReactNode;
}) => ReactNode;
};Configuration options for creating a form instance.
interface FormOptions<
TFormData,
TOnMount extends undefined | FormValidateOrFn<TFormData>,
TOnChange extends undefined | FormValidateOrFn<TFormData>,
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
TSubmitMeta,
> extends BaseFormOptions<TFormData, TSubmitMeta> {
/** Form-level validators */
validators?: FormValidators<
TFormData,
TOnMount,
TOnChange,
TOnChangeAsync,
TOnBlur,
TOnBlurAsync,
TOnSubmit,
TOnSubmitAsync,
TOnDynamic,
TOnDynamicAsync,
TOnServer
>;
/** Form transformation configuration */
transform?: FormTransform<
TFormData,
TOnMount,
TOnChange,
TOnChangeAsync,
TOnBlur,
TOnBlurAsync,
TOnSubmit,
TOnSubmitAsync,
TOnDynamic,
TOnDynamicAsync,
TOnServer,
TSubmitMeta
>;
/** Form identifier used for devtools and debugging */
formId?: string;
/** If true, allows form submission even when validation fails */
canSubmitWhenInvalid?: boolean;
/** Debounce time in milliseconds for async validation */
asyncDebounceMs?: number;
/** Whether to always run async validation */
asyncAlways?: boolean;
/** Initial form values */
defaultValues?: TFormData;
/** Initial form state */
defaultState?: Partial<FormState<TFormData, ...>>;
/** Custom validation logic function */
validationLogic?: ValidationLogicFn;
/**
* Submit handler called when form is valid
* @param props - Object containing form value, API instance, and optional metadata
*/
onSubmit?: (props: {
value: TFormData;
formApi: FormApi<TFormData, ...>;
meta?: TSubmitMeta;
}) => any | Promise<any>;
/**
* Handler called when form submission is attempted but form is invalid
* @param props - Object containing form API instance
*/
onSubmitInvalid?: (props: {
value: TFormData;
formApi: FormApi<TFormData, ...>;
}) => void;
/** Form-level lifecycle event listeners */
listeners?: FormListeners<
TFormData,
TOnMount,
TOnChange,
TOnChangeAsync,
TOnBlur,
TOnBlurAsync,
TOnSubmit,
TOnSubmitAsync,
TOnDynamic,
TOnDynamicAsync,
TOnServer,
TSubmitMeta
>;
}
interface BaseFormOptions<TFormData, TSubmitMeta> {
/** Initial form values */
defaultValues?: TFormData;
/** Metadata passed from handleSubmit to onSubmit function */
onSubmitMeta?: TSubmitMeta;
}Complete form state interface with base and derived properties.
interface FormState<
TFormData,
TOnMount extends undefined | FormValidateOrFn<TFormData>,
TOnChange extends undefined | FormValidateOrFn<TFormData>,
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
> extends BaseFormState<TFormData, ...>,
DerivedFormState<TFormData, ...> {}
interface BaseFormState<TFormData, ...> {
/** Current form values */
values: TFormData;
/** Map of form-level validation errors by trigger type */
errorMap: ValidationErrorMap<...>;
/** Metadata for validation execution by trigger type */
validationMetaMap: Record<ValidationErrorMapKeys, ValidationMeta | undefined>;
/** Record of base field metadata for each field (not including derived properties) */
fieldMetaBase: Record<DeepKeys<TFormData>, AnyFieldMetaBase>;
/** Whether the form is currently submitting (after handleSubmit, before onSubmit completes) */
isSubmitting: boolean;
/** Whether the onSubmit function has completed successfully */
isSubmitted: boolean;
/** Whether the form or any fields are currently validating */
isValidating: boolean;
/** Number of times submission has been attempted */
submissionAttempts: number;
/** Whether the last submission was successful */
isSubmitSuccessful: boolean;
}
interface DerivedFormState<TFormData, ...> {
/** Form-level validation errors array */
errors: ValidationError[];
/** Map of field metadata with derived properties keyed by field path */
fieldMeta: Record<DeepKeys<TFormData>, FieldMeta<any, any, any, ...>>;
/** Whether the form can be submitted (valid and not submitting) */
canSubmit: boolean;
/** Whether any field has been touched */
isTouched: boolean;
/** Whether the form is in its initial state */
isPristine: boolean;
/** Whether the form has been modified from initial state */
isDirty: boolean;
/** Whether the form is valid (no errors at form or field level) */
isValid: boolean;
}Form-level validator configuration.
interface FormValidators<
TFormData,
TOnMount extends undefined | FormValidateOrFn<TFormData>,
TOnChange extends undefined | FormValidateOrFn<TFormData>,
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
> {
/** Validator that runs when form is mounted */
onMount?: TOnMount;
/** Validator that runs when form values change */
onChange?: TOnChange;
/** Async validator that runs when form values change */
onChangeAsync?: TOnChangeAsync;
/** Validator that runs when a field is blurred */
onBlur?: TOnBlur;
/** Async validator that runs when a field is blurred */
onBlurAsync?: TOnBlurAsync;
/** Validator that runs on form submission */
onSubmit?: TOnSubmit;
/** Async validator that runs on form submission */
onSubmitAsync?: TOnSubmitAsync;
/** Validator that runs dynamically based on validation logic */
onDynamic?: TOnDynamic;
/** Async validator that runs dynamically based on validation logic */
onDynamicAsync?: TOnDynamicAsync;
/** Server-side validator (used with framework integrations) */
onServer?: TOnServer;
}Event listener configuration for form lifecycle events.
interface FormListeners<TFormData, ...> {
/**
* Listener called when form is mounted
* @param props.formApi - Form API instance
*/
onMount?: (props: {
formApi: FormApi<TFormData, ...>;
}) => void;
/**
* Listener called when form values change
* @param props.formApi - Form API instance
* @param props.fieldApi - Field API that triggered the change
*/
onChange?: (props: {
formApi: FormApi<TFormData, ...>;
fieldApi: AnyFieldApi;
}) => void;
/** Debounce time in milliseconds for onChange listener */
onChangeDebounceMs?: number;
/**
* Listener called when a field is blurred
* @param props.formApi - Form API instance
* @param props.fieldApi - Field API that was blurred
*/
onBlur?: (props: {
formApi: FormApi<TFormData, ...>;
fieldApi: AnyFieldApi;
}) => void;
/** Debounce time in milliseconds for onBlur listener */
onBlurDebounceMs?: number;
/**
* Listener called on form submission
* @param props.formApi - Form API instance
* @param props.meta - Submit metadata
*/
onSubmit?: (props: {
formApi: FormApi<TFormData, ...>;
meta: TSubmitMeta;
}) => void;
}/**
* Synchronous form validation function
* @param props.value - Current form values
* @param props.formApi - Form API instance
* @returns Validation error or undefined if valid
*/
type FormValidateFn<TFormData> = (props: {
value: TFormData;
formApi: FormApi<TFormData, ...>;
}) => ValidationError | Promise<ValidationError>;
/**
* Asynchronous form validation function with abort signal support
* @param props.value - Current form values
* @param props.signal - AbortSignal for cancellation
* @param props.formApi - Form API instance
* @returns Promise resolving to validation error or undefined if valid
*/
type FormValidateAsyncFn<TFormData> = (props: {
value: TFormData;
signal: AbortSignal;
formApi: FormApi<TFormData, ...>;
}) => ValidationError | Promise<ValidationError>;
/** Union of validation function or Standard Schema validator */
type FormValidateOrFn<TFormData> =
| FormValidateFn<TFormData>
| StandardSchemaV1<TFormData, TFormData>;
/** Union of async validation function or Standard Schema validator */
type FormAsyncValidateOrFn<TFormData> =
| FormValidateAsyncFn<TFormData>
| StandardSchemaV1<TFormData, TFormData>;Types for tracking validation state and field information.
/**
* Validation metadata for tracking async validation state
* Stores an abort controller to cancel previous async validation attempts
*/
type ValidationMeta = {
/** AbortController stored in memory to cancel previous async validation attempts */
lastAbortController: AbortController;
};
/**
* Field information object containing field instance and validation metadata
* Accessible via form.fieldInfo[fieldName]
*/
type FieldInfo<TFormData> = {
/** Field API instance or null if field is not currently mounted */
instance: FieldApi<TFormData, any, any, ...> | null;
/** Validation metadata by trigger type for this field */
validationMetaMap: Record<ValidationErrorMapKeys, ValidationMeta | undefined>;
};Type aliases for convenience when working with forms without needing to specify all generic parameters.
/**
* FormApi with all generics set to any for convenience in dynamic or loosely-typed contexts
* Useful when you need to work with forms of unknown structure
*/
type AnyFormApi = FormApi<any, any, any, any, any, any, any, any, any, any, any, any>;
/**
* FormState with all generics set to any for convenience
* Useful for generic form state handling
*/
type AnyFormState = FormState<any, any, any, any, any, any, any, any, any, any, any>;
/**
* FormOptions with all generics set to any for convenience
* Useful when passing form options dynamically
*/
type AnyFormOptions = FormOptions<any, any, any, any, any, any, any, any, any, any, any, any>;import { useForm } from '@tanstack/react-form';
function ContactForm() {
const form = useForm({
defaultValues: {
name: '',
email: '',
message: '',
},
validators: {
onChange: ({ value }) => {
if (!value.email.includes('@')) {
return { form: 'Invalid email' };
}
return undefined;
},
},
onSubmit: async ({ value }) => {
await fetch('/api/contact', {
method: 'POST',
body: JSON.stringify(value),
});
},
});
return (
<form onSubmit={(e) => {
e.preventDefault();
form.handleSubmit();
}}>
{/* Field components */}
</form>
);
}const form = useForm({
defaultValues: {
username: '',
},
asyncDebounceMs: 500,
validators: {
onChangeAsync: async ({ value, signal }) => {
const response = await fetch(
`/api/check-username?username=${value.username}`,
{ signal }
);
const data = await response.json();
return data.available ? undefined : 'Username already taken';
},
},
});function FormStatus() {
const form = useForm({ /* ... */ });
return (
<form.Subscribe
selector={(state) => ({
canSubmit: state.canSubmit,
isSubmitting: state.isSubmitting,
errors: state.errors,
})}
>
{({ canSubmit, isSubmitting, errors }) => (
<div>
<button type="submit" disabled={!canSubmit || isSubmitting}>
{isSubmitting ? 'Submitting...' : 'Submit'}
</button>
{errors.map((error, i) => (
<div key={i}>{String(error)}</div>
))}
</div>
)}
</form.Subscribe>
);
}const form = useForm({
defaultValues: {
todos: [{ text: '', completed: false }],
},
});
// Add new todo
form.pushFieldValue('todos', { text: '', completed: false });
// Remove todo at index
form.removeFieldValue('todos', 1);
// Move todo from index 0 to index 2
form.moveFieldValues('todos', 0, 2);
// Clear all todos
form.clearFieldValues('todos');Install with Tessl CLI
npx tessl i tessl/npm-tanstack--react-form