Skip to main content
TanStack Form is unlike most form libraries you’ve used before. It’s designed for large-scale production usage, with a focus on type safety, performance and composition for an unmatched developer experience. As a result, we’ve developed a philosophy around the library’s usage that values scalability and long-term developer experience over short and sharable code snippets.

Installation

1

Install the package

Install @tanstack/react-form using your package manager:
npm install @tanstack/react-form
2

Create your first form

Here’s a basic example of a form using useForm and form.Field:
import { useForm } from '@tanstack/react-form'

function App() {
  const form = useForm({
    defaultValues: {
      firstName: '',
      lastName: '',
    },
    onSubmit: async ({ value }) => {
      // Do something with form data
      console.log(value)
    },
  })
  
  return (
    <form
      onSubmit={(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,
        }}
        children={(field) => (
          <>
            <label htmlFor={field.name}>First Name:</label>
            <input
              id={field.name}
              name={field.name}
              value={field.state.value}
              onBlur={field.handleBlur}
              onChange={(e) => field.handleChange(e.target.value)}
            />
            {field.state.meta.isTouched && !field.state.meta.isValid ? (
              <em>{field.state.meta.errors.join(',')}</em>
            ) : null}
          </>
        )}
      />
      
      <form.Subscribe
        selector={(state) => [state.canSubmit, state.isSubmitting]}
        children={([canSubmit, isSubmitting]) => (
          <button type="submit" disabled={!canSubmit}>
            {isSubmitting ? '...' : 'Submit'}
          </button>
        )}
      />
    </form>
  )
}
3

Add validation

You can add synchronous and asynchronous validation to your fields:
<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,
    onChangeAsyncDebounceMs: 500,
    onChangeAsync: async ({ value }) => {
      await new Promise((resolve) => setTimeout(resolve, 1000))
      return (
        value.includes('error') && 'No "error" allowed in first name'
      )
    },
  }}
  children={(field) => (
    <>
      <label htmlFor={field.name}>First Name:</label>
      <input
        id={field.name}
        name={field.name}
        value={field.state.value}
        onBlur={field.handleBlur}
        onChange={(e) => field.handleChange(e.target.value)}
      />
      {field.state.meta.isTouched && !field.state.meta.isValid ? (
        <em>{field.state.meta.errors.join(',')}</em>
      ) : null}
    </>
  )}
/>

Advanced Usage with Form Composition

For production applications, we recommend using createFormHook to reduce boilerplate and improve type safety:
import { createFormHook, createFormHookContexts } from '@tanstack/react-form'
import { z } from 'zod'

const { fieldContext, formContext } = createFormHookContexts()

const { useAppForm } = createFormHook({
  fieldComponents: {
    TextField,
    NumberField,
  },
  formComponents: {
    SubmitButton,
  },
  fieldContext,
  formContext,
})

function App() {
  const form = useAppForm({
    defaultValues: {
      username: '',
      age: 0,
    },
    validators: {
      onChange: z.object({
        username: z.string(),
        age: z.number().min(13),
      }),
    },
    onSubmit: ({ value }) => {
      alert(JSON.stringify(value, null, 2))
    },
  })

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault()
        form.handleSubmit()
      }}
    >
      <h1>Personal Information</h1>
      <form.AppField
        name="username"
        children={(field) => <field.TextField label="Full Name" />}
      />
      <form.AppField
        name="age"
        children={(field) => <field.NumberField label="Age" />}
      />
      <form.AppForm>
        <form.SubmitButton />
      </form.AppForm>
    </form>
  )
}

Next Steps

Build docs developers (and LLMs) love