Building Accessible React Forms with React Hook Form and Zod
A practical guide to forms that are validated, keyboard-friendly, and genuinely accessible — without fighting the framework.
Forms are where accessibility quietly succeeds or fails. React Hook Form and Zod give you a clean way to get validation right, but accessibility still takes intent. Here's the setup I reach for.
Schema first with Zod
Define the shape and rules in one place, then infer your types from it. Your validation and your TypeScript stay in sync automatically.
const schema = z.object({
email: z.string().email('Enter a valid email'),
message: z.string().min(10, 'Tell me a little more'),
});Wire errors to the right ARIA
Every input needs a real label, and every error needs to be announced. Connect them explicitly so assistive tech reads the message the moment it appears.
- Associate labels with inputs via htmlFor / id — never rely on placement alone.
- Set aria-invalid on fields that fail validation.
- Point aria-describedby at the error element so it's read aloud.
- Move focus to the first invalid field on submit.
Respect the keyboard
Test the whole form with the mouse unplugged. Tab order should be logical, focus states must be visible, and Enter should submit from any field. If you can't complete it on the keyboard, it isn't done.
Accessible forms aren't a separate feature — they're just forms built correctly.
Have a product or frontend challenge worth discussing?
I'm always happy to talk through interface, motion, or engineering problems.
Start a conversationKeep reading
All articlesDesigning Clear Filters for Data-Heavy Products
Filtering is where data products live or die. A look at patterns that keep dense interfaces calm, scannable, and fast to operate.
· 9 min readUsing Motion Without Making a Portfolio Feel Unprofessional
Motion should support meaning, not perform tricks. Where to add it, where to hold back, and how to keep things feeling composed.
· 8 min read