Back to DocsRecipe

Accessible form validation

Real-time inline validation with screen-reader announcements, error summaries, and focus management — no ARIA left behind.

Pattern overview

  • aria-describedby links each input to its live-region error container.
  • role="alert" on the error summary ensures AT announces it immediately.
  • Focus is sent to the first invalid field on submit, then to the summary on correction.
  • Error messages use aria-live="polite" for inline updates without interrupting the user.

Code skeleton

<form noValidate onSubmit={handleSubmit}>
  <div role="alert" tabIndex={-1} ref={summaryRef}>
    {errors.length} error{errors.length !== 1 && "s"}
  </div>

  <label htmlFor="email">Email</label>
  <input
    id="email"
    type="email"
    aria-describedby="email-err"
    aria-invalid={!!emailError}
    ref={emailRef}
  />
  <span id="email-err" role="status" aria-live="polite">
    {emailError}
  </span>

  <button type="submit">Subscribe</button>
</form>

Key takeaways

  • Always pair client-side validation with server-side checks — never trust the browser alone.
  • Use live regions sparingly; only the changed error text should update, not the entire form.
  • Test with VoiceOver, NVDA, and keyboard-only navigation before shipping.