Using react-hook-form
In this page:
const { register, handleSubmit, formState: { errors } } = useForm();
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("fieldName", { required: "Message" })} />
{errors.fieldName && <p>{errors.fieldName.message}</p>}
</form>
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.
Example: Why Use a Form Library
// 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.
Example: Registering Inputs with register()
// 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.
Example: Reading Validation Errors from formState
// 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.
- Forgetting to spread {...register(fieldName)} onto the input, which disconnects it from the form's tracking.
- Mixing react-hook-form's uncontrolled approach with manual useState for the same field.
- Not reading errors from formState, so validation messages never show up.
- 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.
Requires npm install react-hook-form — not available via CDN in this sandbox; works with React 16.8+ (uses hooks internally).
Chapter Quiz — Complete all 8 topics to unlock
0/8 topics done
Complete these topics first: