Skip to main content
The useForm composable is the primary way to create and manage forms in Vue applications using TanStack Form.

Import

import { useForm } from '@tanstack/vue-form'

Signature

function useForm<
  TParentData,
  TFormOnMount extends undefined | FormValidateOrFn<TParentData>,
  TFormOnChange extends undefined | FormValidateOrFn<TParentData>,
  TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
  TFormOnBlur extends undefined | FormValidateOrFn<TParentData>,
  TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
  TFormOnSubmit extends undefined | FormValidateOrFn<TParentData>,
  TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
  TFormOnDynamic extends undefined | FormValidateOrFn<TParentData>,
  TFormOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
  TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData>,
  TSubmitMeta,
>(
  opts?: FormOptions<
    TParentData,
    TFormOnMount,
    TFormOnChange,
    TFormOnChangeAsync,
    TFormOnBlur,
    TFormOnBlurAsync,
    TFormOnSubmit,
    TFormOnSubmitAsync,
    TFormOnDynamic,
    TFormOnDynamicAsync,
    TFormOnServer,
    TSubmitMeta
  >,
): VueFormExtendedApi<...>

Parameters

opts
FormOptions<TFormData>
Optional configuration object for the form.
opts.defaultValues
TFormData
Initial values for the form fields.
opts.onSubmit
(values: FormSubmitData<TFormData>) => void | Promise<void>
Callback function called when the form is submitted.
opts.validators
FormValidators<TFormData>
Validation functions for the form.
opts.validators.onChange
FormValidateOrFn<TFormData>
Validator that runs on every change.
opts.validators.onChangeAsync
FormAsyncValidateOrFn<TFormData>
Async validator that runs on change with debouncing.
opts.validators.onBlur
FormValidateOrFn<TFormData>
Validator that runs when the form loses focus.
opts.validators.onMount
FormValidateOrFn<TFormData>
Validator that runs when the form is mounted.

Return Value

api
VueFormExtendedApi<TFormData>
The form API instance with Vue-specific extensions.
Field
FieldComponent<TFormData>
A Vue component for rendering individual form fields.
useField
UseField<TFormData>
A composable for creating and managing individual fields.
useStore
(selector?) => Readonly<Ref<TSelected>>
A composable for subscribing to form state changes.
Subscribe
Component
A component for subscribing to form state.
handleSubmit
() => void
Function to trigger form submission.
reset
() => void
Function to reset the form to its initial state.
state
FormState<TFormData>
Current state of the form including values, errors, and validation status.

Usage Example

<script setup lang="ts">
import { useForm } from '@tanstack/vue-form'

interface FormData {
  firstName: string
  lastName: string
}

const form = useForm<FormData>({
  defaultValues: {
    firstName: '',
    lastName: '',
  },
  onSubmit: async ({ value }) => {
    // Submit form data
    console.log('Form submitted:', value)
  },
})
</script>

<template>
  <form
    @submit="
      (e) => {
        e.preventDefault()
        e.stopPropagation()
        form.handleSubmit()
      }
    "
  >
    <form.Field
      name="firstName"
      :validators="{
        onChange: ({ value }) =>
          !value
            ? 'A first name is required'
            : value.length < 3
              ? 'First name must be at least 3 characters'
              : undefined,
      }"
    >
      <template v-slot="{ field, state }">
        <label :htmlFor="field.name">First Name:</label>
        <input
          :id="field.name"
          :name="field.name"
          :value="field.state.value"
          @input="
            (e) => field.handleChange((e.target as HTMLInputElement).value)
          "
          @blur="field.handleBlur"
        />
        <div v-if="state.meta.errors.length" style="color: red">
          {{ state.meta.errors[0] }}
        </div>
      </template>
    </form.Field>

    <form.Subscribe>
      <template v-slot="{ canSubmit, isSubmitting }">
        <button type="submit" :disabled="!canSubmit">
          {{ isSubmitting ? '...' : 'Submit' }}
        </button>
      </template>
    </form.Subscribe>
  </form>
</template>

See Also

Build docs developers (and LLMs) love