Accessible form validation
Forgiving, accessible validation: check at the right moment, tie plain-language errors to fields with aria, summarize them — never signal by color alone.
In one line: validate at a forgiving moment, say what's wrong in plain language, wire the message to its field with aria-describedby + aria-invalid, and summarize the errors — so everyone, keyboard and screen reader included, can recover.
What it is
Validation is the conversation a form has with someone filling it out. Done badly it nags on every keystroke, turns the field red with no explanation, or scrolls a screen-reader user past errors they never heard about. Done well it waits for a sensible moment, explains the problem, and points the way to fix it.
Three things make it accessible: timing (when you check), association (connecting the error to the field for assistive tech), and summary (a roundup that links to each problem at the top of the form).
Why it matters
Forms are where tasks succeed or fail — signups, checkouts, support requests. An inaccessible error is a wall: a screen-reader user who can't perceive that a field is invalid, or why, simply can't complete the task. Color-only error styling fails colour-blind users outright (WCAG 1.4.1).
Forgiving timing matters for everyone. Validating on every keystroke flags "invalid email" while someone is still typing the first letter — anxious and useless. Waiting until they've had a fair attempt respects their effort.
See it
Tweak it2
Submit with the pre-filled invalid email to see the inline error, the aria-invalid state, and the linked summary. Switch the timing between on-submit, on-blur, and as-you-type to feel which respects the user.
How it works
Timing. The forgiving default is: validate on submit, and after a field's first failed attempt, re-validate it on blur (so it can turn green as soon as it's fixed). Validating on every input event is reserved for cases where instant feedback genuinely helps, like a password-strength meter.
Association. On an invalid field set aria-invalid="true" and aria-describedby="<id of the error>", with the error text in an element carrying that id. Now a screen reader announces the field, its state, and the reason together. Use novalidate on the form so you control the messaging instead of the browser's terse bubbles.
Summary & focus. On a failed submit, render an error summary — a short list of links, each jumping to a field — and move focus to it (or to the first invalid field). That gives keyboard and screen-reader users a map of what to fix and a one-key route to each.
Build it
<form novalidate>
<!-- Error summary, rendered on a failed submit, focus moved here. -->
<div role="alert" id="summary" hidden>
<p>Please fix 1 field:</p>
<a href="#email">That doesn't look like an email address.</a>
</div>
<label for="email">Email address</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
/>
<!-- Tied to the input via aria-describedby; not color-only. -->
<p id="email-error">That doesn't look like an email address.</p>
<button type="submit">Create account</button>
</form>Make it yours
Use the controls beside the demo above to change validate and show error summary — each change updates the example live.
Experiment in the playground- Switch to as you type and feel how it nags before you've finished — then back to on submit / on blur, the forgiving default.
- Toggle the summary off and on: for a long form, that linked roundup is how a keyboard user finds every problem fast.
- The error text isn't just a red border — it's words, tied to the field, so it works without sight or color.
Reproduce it with an LLM
Reproduce it with an LLM
You are a senior front-end engineer who follows WCAG and the ARIA Authoring Practices. Build an email field with accessible, forgiving inline validation: validate on submit and, after the first attempt, on blur — never on every keystroke. When invalid, set `aria-invalid="true"`, link a specific, plain-language error message to the input with `aria-describedby`, and move focus to the first invalid field on submit. Add an error summary at the top of the form (a list of links that jump to each field). Use a real `<label>`, `novalidate` so you control messaging, and never rely on color alone to signal the error. Return only the component code with imports.
Pitfalls & accessibility
Related
Fieldsets, legends & grouping
Use fieldset and legend to give related controls a shared accessible name — and learn when grouping helps, when it hurts, and the ARIA fallback.
Live regions
When content changes without a page load, a screen reader only knows if you tell it. Learn aria-live, polite vs assertive, and the rules that make it work.