TanStack Form logo

TanStack Form

A powerful, type-safe, and headless form management library designed for maximum flexibility and TypeScript inference.

npm install @tanstack/react-form
6.1K529.4K/weekv1.26.0263.65 KBMIT162 issues
Last updated: 2025-11-25
Star history chart for TanStack/form

TL;DR

A comprehensive form state manager that is 100% headless, meaning it provides the logic and state handling without enforcing any UI markup.

Part of the renowned TanStack family, it offers best-in-class TypeScript support and a framework-agnostic core that works across React, Vue, and Solid.

Why TanStack Form?

TanStack Form represents the modern evolution of form state management, built by the same team behind TanStack Query. It prioritizes correctness and developer experience through deep type safety.

  • Deep Type Safety: It doesn't just validate types at the top level; it deeply infers types for nested objects and arrays, providing autocomplete for field names and validation errors that is superior to almost any other library.
  • Headless Architecture: It provides zero markup. You are responsible for the UI, which gives you complete freedom to integrate with Shadcn UI, MUI, or your own custom design system without fighting default styles.
  • Granular Subscriptions: Unlike older libraries that re-render the whole form on change, TanStack Form allows components to subscribe only to the specific slices of state they need (e.g., just the error message of one field).
  • Framework Agnostic: The core logic is written in vanilla JS. If your team moves from React to Solid or Vue, 90% of your form logic knowledge transfers over.
  • Validator Agnostic: It has first-class support for Zod, Yup, and standard validator functions, allowing you to mix and match synchronous and asynchronous validation easily.

Code Snippet

TanStack Form uses a hook-based API combined with a Field component that utilizes the "Render Prop" pattern. This ensures that field.state is always up-to-date and strictly typed.

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

export default function SignupForm() {
  const form = useForm({
    defaultValues: {
      email: '',
      age: 0,
    },
    onSubmit: async ({ value }) => {
      // Type-safe 'value' here
      console.log(value)
    },
  })

  return (
    <div>
      <form
        onSubmit={(e) => {
          e.preventDefault()
          e.stopPropagation()
          form.handleSubmit()
        }}
        className="flex flex-col gap-4"
      >
        {/* Field Component Pattern */}
        <form.Field
          name="email"
          validators={{
            onChange: ({ value }) => !value.includes('@') ? 'Invalid email' : undefined,
          }}
          children={(field) => (
            <div>
              <label>Email</label>
              <input
                name={field.name}
                value={field.state.value}
                onBlur={field.handleBlur}
                onChange={(e) => field.handleChange(e.target.value)}
                className="border p-2"
              />
              {field.state.meta.errors ? (
                <em role="alert" className="text-red-500">{field.state.meta.errors.join(', ')}</em>
              ) : null}
            </div>
          )}
        />

        {/* Subscribe to form-level state */}
        <form.Subscribe
          selector={(state) => [state.canSubmit, state.isSubmitting]}
          children={([canSubmit, isSubmitting]) => (
            <button type="submit" disabled={!canSubmit} className="bg-blue-500 text-white p-2">
              {isSubmitting ? 'Submitting...' : 'Submit'}
            </button>
          )}
        />
      </form>
    </div>
  )
}

Pros and Cons

No library is perfect; understanding the trade-offs is key to selecting the right tool.

Pros

  • DX & TypeScript: The autocomplete experience when typing field.name is unmatched. If you rename a field in your data schema, your TS compiler will instantly flag all broken form fields.
  • Performance: By using the Subscribe component or specific field subscriptions, it achieves fine-grained reactivity similar to signals-based architectures.
  • TanStack Ecosystem: If you already use TanStack Query or Table, the API design patterns will feel very familiar and consistent.

Cons

  • Verbosity: The Render Prop pattern (children={(field) => ...}) is more verbose than the simple register spread operator found in React Hook Form.
  • Newer Ecosystem: While growing fast, it doesn't yet have the massive library of third-party wrappers and StackOverflow answers that React Hook Form possesses.
  • Documentation: As a newer library, the documentation is sometimes less comprehensive regarding edge cases compared to mature tools like Formik.

Comparison with Other Form Libraries

The table below outlines the positioning differences between TanStack Form and other popular libraries:

LibraryDesign PhilosophyBest ForPain Points
TanStack FormHeadless / TS-First
Prioritizes type inference and granular state subscription.
TypeScript Heavy Teams
Teams who want strictly typed forms and full UI control.
Verbosity
Writing render functions for every input can feel repetitive.
React Hook FormUncontrolled / Concise
Uses refs to minimize code and re-renders.
Rapid Development
Getting simple to medium forms up and running with minimal code.
Complex Data
Deeply nested or dynamic data structures can sometimes be tricky to type perfectly.
FormikControlled / Classic
The original standard for React forms using controlled state.
Legacy Projects
Maintaining older codebases where performance is not the primary bottleneck.
Performance
Re-renders the entire form tree too often; development has slowed down significantly.

Verdict: When to Adopt

Choose TanStack Form if you are building a complex application where TypeScript safety is your #1 priority, or if you need a solution that decouples logic from the React view layer (e.g., for sharing logic with other frameworks). If you prefer brevity and less markup, React Hook Form might still be the faster choice.