Forms are where most React apps do their real work: collecting, validating, and submitting user input, from a login screen to a multi-page checkout. React Hook Form handles field registration and form state with minimal re-renders by leaning on uncontrolled, ref-based inputs, while Zod supplies a single TypeScript-first schema that both validates the data and infers its type, so the shape you validate against is the shape your code actually sees. Together, via a thin resolver adapter, they cover the vast majority of production form needs; Formik, TanStack Form, Formisch, and Conform exist for teams who want a different tradeoff between boilerplate, type-safety, and progressive enhancement. The non-obvious mental model to keep in mind: React Hook Form stores values outside React state by default, so a value only becomes visible to your components (for conditional rendering, live previews, cross-field checks) once you explicitly subscribe to it with watch, useWatch, or Controller.
What This Cheat Sheet Covers
This topic spans 13 focused tables and 108 indexed concepts. Below is a complete table-by-table outline of this topic, spanning foundational concepts through advanced details.
A jump-to index of every table row in this cheat sheet.
An interactive map of every table and concept in this topic.
Table 1: Getting Started with React Hook Form
React Hook Form's core API is a single hook that registers inputs and hands back submission and state helpers; everything else in the library builds on these few primitives.
| Concept | Example | Description |
|---|---|---|
const { register, handleSubmit, formState } = useForm() | Primary hook that creates and manages a form instance; accepts an optional config object ( defaultValues, mode, resolver, etc). | |
<input {...register("email", { required: true })} /> | Registers a native input into the form; wires up ref, name, onChange, and onBlur and returns the value under that key on submit. | |
<form onSubmit={handleSubmit(onValid, onInvalid)}> | Wraps your submit handler so validation runs first; only calls onValid when the form passes validation. | |
useForm({ defaultValues: { email: "" } }) | Seeds initial field values and acts as the single source of truth the library compares against for isDirty/dirtyFields. |