React Hook Form logo

React Hook Form

High-performance form validation library for React that embraces uncontrolled components to minimize re-renders.

npm install react-hook-form
44.2K17.7M/weekv7.67.01.14 MBMIT125 issues
Last updated: 2025-11-29
Star history chart for react-hook-form/react-hook-form

TL;DR

A performance-focused library that leverages uncontrolled components and native HTML inputs to register form state, drastically reducing re-renders compared to controlled alternatives.

Lightweight, zero-dependency, and TypeScript-first, it offers seamless integration with schema validation libraries like Zod or Yup via a simple resolver pattern.

Why React Hook Form?

React Hook Form fundamentally changes how developers handle form state by embracing the "uncontrolled" component pattern. Instead of updating a state variable on every keystroke, it references the DOM nodes directly.

  • Isolating Re-renders: The library's architecture ensures that changing a single input doesn't trigger a re-render of the entire form tree. This is a game-changer for complex forms with many fields.
  • Less Boilerplate: By registering inputs directly into the hook, you eliminate the repetitive value={state} and onChange={setState} logic required by controlled forms.
  • Seamless Validation Integration: It decouples validation logic from UI logic. Through its resolver architecture, you can drop in Zod, Yup, or Joi schemas effortlessly.
  • Tiny Bundle Size: It is significantly lighter than many legacy form libraries, with zero dependencies, keeping your application's initial load fast.
  • Developer Experience (DX): The API is intuitive for standard HTML inputs, making it incredibly fast to scaffold working forms with validation.

Code Snippet

This example demonstrates the standard v7 usage: registering inputs, handling submission, and displaying validation errors. Note how clean the JSX is without manual state bindings.

import { useForm } from "react-hook-form";

export default function LoginForm() {
  // "register" connects the input to RHF
  // "handleSubmit" validates inputs before invoking the callback
  // "formState" subscribes to specific form properties
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
  } = useForm();

  const onSubmit = (data) => {
    console.log("Form Data:", data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-4">
      {/* Basic Input Registration */}
      <div>
        <label>Email</label>
        <input
          {...register("email", { required: "Email is required" })}
          className="border p-2"
        />
        {errors.email && <span className="text-red-500">{errors.email.message}</span>}
      </div>

      {/* Validation with native rules */}
      <div>
        <label>Password</label>
        <input
          type="password"
          {...register("password", { minLength: { value: 6, message: "Min 6 chars" } })}
          className="border p-2"
        />
        {errors.password && <span className="text-red-500">{errors.password.message}</span>}
      </div>

      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? "Logging in..." : "Login"}
      </button>
    </form>
  );
}

In this pattern, the component does not re-render on every keystroke inside the inputs. It only re-renders when validation errors change (because we destructured errors) or when the form submission state changes.

Pros and Cons

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

Pros

  • Performance: The undisputed king of rendering performance. It bypasses React's virtual DOM diffing for input values, resulting in snappy interactions even on low-end devices.
  • Subscription-Based Proxy: You only "pay" for the state you use. If you don't destructure formState.isDirty, your component won't re-render when dirty state changes.
  • Adoption: It is currently the most active and widely used form solution in the React ecosystem, meaning excellent community support and abundant resources.

Cons

  • UI Library Integration: Using React Hook Form with controlled UI libraries (like Material UI, Ant Design) requires the Controller wrapper component. This adds verbosity and reintroduces some "controlled" overhead.
  • Mental Model Shift: Developers used to the "React Way" (Controlled components) might find it initially unintuitive to not have immediate access to input values in state without calling getValues() or watch().
  • Complex Deeply Nested Forms: While supported, managing heavily nested array fields with dynamic appending/prepending can become verbose compared to state-tree solutions like Formily.

Comparison with Other Form Libraries

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

LibraryDesign PhilosophyBest ForPain Points
React Hook FormUncontrolled / Perf-First
Leverages DOM refs to minimize React re-renders.
Production Standards
The default choice for most modern React apps, especially those sensitive to performance.
UI Kit Wrappers
Requires Controller boilerplate when wrapping components like generic DatePickers.
FormikControlled / Explicit
The classic "React way" of handling forms with predictable state updates.
Legacy / Simple Forms
Good for simple forms if you are maintaining older codebases.
Performance
Triggers a re-render of the entire form tree on every single keystroke by default.
TanStack FormHeadless / Agnostic
Framework-agnostic core that separates logic completely from UI.
Complex Architecture
Teams needing a unified form logic across React, Vue, and Solid.
Newer Ecosystem
Less community content and examples compared to the massive RHF ecosystem.

Ecosystem & Extensions

React Hook Form has a modular design, keeping the core small while enabling powerful extensions:

  • @hookform/resolvers: The essential companion package. It allows you to use schema validation libraries like Zod, Yup, Superstruct, and Joi directly with the useForm hook.
  • @hookform/devtools: A dedicated component to visualize form state, errors, and dirty fields in real-time during development.
  • react-hook-form-persist: Simple utilities to persist form state to local storage or session storage.