ReactIntermediate6h

Forms in React.

React Hook Form + Zod — controlled, validated, accessible.

What is it?

Real-world React forms — signup, checkout, settings — need state, validation, async submission, and error handling. Doing it from scratch with useState per field works for small forms; React Hook Form + Zod is the 2026 default for anything bigger. RHF handles state and focus, Zod owns the validation schema and types.

Why it matters

Forms convert. A signup form with mismatched validation, jumpy errors, or stale data after submit drops conversion measurably. RHF's performance (uncontrolled inputs, no re-render per keystroke) and Zod's type-safe schemas are 80% of the modern stack — interview teams expect fluency.

What to learn

  • Why uncontrolled inputs scale better than controlled in big forms
  • React Hook Form: register, handleSubmit, formState.errors
  • Zod schemas: z.object({ email: z.string().email() })
  • The zodResolver bridge between RHF and Zod
  • Async validation (e.g. "is this username taken?")
  • Error messaging UX: when to show errors, where to put them
  • Accessibility: aria-invalid, aria-describedby, error association

Common pitfall

Using a controlled input (useState + onChange) for every field in a 50-field form. Every keystroke re-renders the whole form. RHF uses uncontrolled inputs by default — the form re-renders only on submit or errors. The performance gap is real.

Resources

Primary (free):

Practice

Build a signup form with email, password, password-confirm, and a terms-of-service checkbox. Use RHF + Zod. Validate that passwords match (cross-field validation). Show inline errors below each field, only after the user blurs that field. Done when the form is fully accessible (label + error association) and submits clean data.

Outcomes

  • Set up React Hook Form + Zod on a fresh form in under 10 minutes.
  • Write a Zod schema with cross-field validation (passwords, dates).
  • Pair every input with a label and an error region.
  • Decide between controlled and uncontrolled inputs with a real reason.
Back to Frontend roadmap