← Back to React Course | Chapter 7: Forms & User Input | Lesson 4 of 8

Using react-hook-form

react-hook-form is like a personal assistant that tracks all your form fields for you so you don't have to write useState for every single one.

Why Use a Form Library

For forms with many fields, writing a useState and onChange handler for every single one becomes repetitive and can cause unnecessary re-renders on every keystroke. react-hook-form manages all field state internally using uncontrolled inputs, exposing a simple register() function instead.

Note: react-hook-form is especially popular for large forms (10+ fields) where performance and boilerplate both matter.

Warning: It's an npm package, not built into React — it needs to be installed and can't run in this CDN-only preview sandbox.

Example: Why Use a Form Library

markup
// Run in your local React project (npm install required)
import { useForm } from 'react-hook-form';

function App() {
  const { register, handleSubmit } = useForm();
  const onSubmit = data => console.log(data);
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('email')} placeholder="Email" />
      <button type="submit">Submit</button>
    </form>
  );
}

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Registering Inputs with register()

Calling register(fieldName) returns the props (ref, onChange, onBlur, name) an input needs to be tracked by the form, without you writing them by hand. Spreading its return value onto an <input> wires that field into the form automatically.

Note: You can pass validation rules directly into register, like register(email, { required: true }).

Warning: Forgetting the spread syntax ({...register(email)}) means only some of the required props get attached, breaking tracking silently.

Example: Registering Inputs with register()

markup
// Run in your local React project (npm install required)
import { useForm } from 'react-hook-form';

function App() {
  const { register, handleSubmit } = useForm();
  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <input {...register('username', { required: true })} />
      <input {...register('age', { min: 18 })} type="number" />
      <button type="submit">Submit</button>
    </form>
  );
}

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Reading Validation Errors from formState

When you add validation rules to register(), react-hook-form automatically tracks any failures in formState.errors, keyed by field name. Destructuring formState.errors alongside register and handleSubmit gives you everything needed to show inline error messages.

Note: Check errors.fieldName && <message> right under each input to keep the error close to the field it belongs to.

Warning: formState.errors resets are timing-sensitive — always read it from the same useForm() call, never store it in separate local state.

Example: Reading Validation Errors from formState

markup
// Run in your local React project (npm install required)
import { useForm } from 'react-hook-form';

function App() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <input {...register('email', { required: 'Email is required' })} />
      {errors.email && <p>{errors.email.message}</p>}
      <button type="submit">Submit</button>
    </form>
  );
}

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Common Mistakes
  1. Forgetting to spread {...register(fieldName)} onto the input, which disconnects it from the form's tracking.
  2. Mixing react-hook-form's uncontrolled approach with manual useState for the same field.
  3. Not reading errors from formState, so validation messages never show up.
Chapter Summary
  • react-hook-form manages form state using uncontrolled inputs and refs internally, minimizing re-renders.
  • The register() function wires an input into the form without needing useState per field.
  • handleSubmit wraps your submit function and only calls it if validation passes.
  • formState.errors holds validation messages keyed by field name.
Browser Support

Requires npm install react-hook-form — not available via CDN in this sandbox; works with React 16.8+ (uses hooks internally).

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.