TanStack/form @tanstack/vue-form@1.29.1
Tags: latest: 1.29.1
References: Docs
API Changes
This section documents version-specific API changes for @tanstack/vue-form.
-
BREAKING:
field.errors— v1.28.0 flattens errors by default ([error]not[[error]]), usedisableErrorFlat: trueto restore old nested behavior source -
DEPRECATED:
field.getValue()— usefield.state.valueinstead as direct accessor methods on FieldApi are deprecated in favor of state access source -
NEW:
field.parseValueWithSchema()— validates field value against Standard Schema V1 without affecting internal field error state source -
NEW:
form.parseValuesWithSchema()— form-level Standard Schema V1 validation helper for third-party schemas like Zod or Valibot source -
NEW:
formOptions()— helper to define reusable, type-safe form options with inference outside of theuseFormhook source -
NEW:
Fieldcomponent — declarative Vue component alternative touseFieldfor defining form fields directly in templates source -
NEW:
Subscribecomponent — Vue component for fine-grained subscriptions to form or field state changes to optimize re-renders source -
NEW:
useStore()— Vue hook providing direct, reactive access to the underlying TanStack Store state for the form or field source -
NEW:
resetField()—FormApimethod to reset a specific field's value and metadata back to its default state source -
NEW:
clearFieldValues()—FormApiutility to efficiently remove all items from an array field's data source -
NEW:
setErrorMap()— allows manual overriding of the internal validation error map for custom validation logic source -
NEW:
StandardSchemaV1— native support for the Standard Schema validation protocol across all validator fields source -
NEW:
modeoption —UseFieldOptionsnow supports explicit'value'or'array'modes for better type safety in complex forms -
NEW:
disableErrorFlat— new option inFieldApiOptionsto opt-out of automatic error flattening introduced in v1.28.0 source
Also changed: resetFieldMeta() new helper · insertFieldValue() array utility · moveFieldValues() array utility · swapFieldValues() array utility · FieldApi.getInfo() metadata helper · VueFieldApi interface stabilization · VueFormApi interface stabilization
Best Practices
- Use
formOptions()to define type-safe, reusable form configurations that can be shared across components or used for better type inference source
tsconst options = formOptions({ defaultValues: { email: '' }, validators: { onChange: z.object({ email: z.string().email() }) } }) const form = useForm(options)
- Link field validations with
onChangeListenToto trigger re-validation when dependent field values change, such as password confirmations source
vue<form.Field name="confirm_password" :validators="{ onChangeListenTo: ['password'], onChange: ({ value, fieldApi }) => value !== fieldApi.form.getFieldValue('password') ? 'Passwords do not match' : undefined }" >
- Implement
async-debounce-msat the field or validator level to throttle expensive asynchronous validation calls like API checks source
vue<form.Field name="username" :async-debounce-ms="500" :validators="{ onChangeAsync: async ({ value }) => checkUsername(value) }" >
- Parse Standard Schemas manually within
onSubmitto retrieve transformed values, as the form state preserves the raw input data source
tsconst form = useForm({ onSubmit: ({ value }) => { // schema.parse converts string to number if transform is defined const validatedData = loginSchema.parse(value) api.submit(validatedData) } })
- Pass custom metadata via
onSubmitMetato differentiate between multiple submission actions within a singleonSubmithandler source
vue<button @click="form.handleSubmit({ action: 'save_draft' })">Save Draft</button> <button @click="form.handleSubmit({ action: 'publish' })">Publish</button>
- Combine
canSubmitwithisPristineto ensure the submit button remains disabled until the user has actually interacted with the form source
vue<template v-slot="{ canSubmit, isPristine }"> <button :disabled="!canSubmit || isPristine">Submit</button> </template>
- Use
form.useStorewith a selector in<script setup>for granular, reactive access to form state without re-rendering on unrelated changes source
tsconst canSubmit = form.useStore((state) => state.canSubmit)
- Enable
asyncAlways: truewhen you need asynchronous validators to execute regardless of whether synchronous validation has already failed source
ts// Runs async validation even if local regex check fails const validators = { onChange: ({ value }) => !value.includes('@') ? 'Invalid' : undefined, onChangeAsync: async ({ value }) => api.check(value), asyncAlways: true }
- Return a
fieldsmapping from form-level validators to update errors across multiple fields simultaneously from a single validation logic source
tsvalidators: { onChange: ({ value }) => ({ fields: { startDate: value.startDate > value.endDate ? 'Must be before end' : undefined, endDate: value.startDate > value.endDate ? 'Must be after start' : undefined } }) }
- Use reactive objects for
defaultValueswhen binding the form to dynamic or asynchronous data sources like TanStack Query source
tsconst { data } = useQuery(...) const defaultValues = reactive({ name: computed(() => data.value?.name ?? '') }) const form = useForm({ defaultValues })

