WCAG 3.3.1 — Error Identification
A form fails to submit, the page is silent. Or a red border lights up with no text. For sighted users, the visual cue is enough; for everyone else, the form has rejected them in a language they can't read.
What this requires
If an input error is automatically detected, the item that is in error must be identified and the error must be described to the user in text. The criterion has two parts: the user needs to know which field is wrong, and why it is wrong, both in text. A red outline alone fails on both counts.
How AI coding tools fail this
When asked to "add validation to this form", AI tools default to
visual-only error state — a red border on the input — without
adding a text message, without linking the error to the field via
aria-describedby, and without setting aria-invalid.
The second pattern: error messages that are present in the DOM but not associated with the field. The text reads "Email is required" somewhere on the page; screen readers don't know which field that applies to.
The third: form-level error summaries with no in-field errors. "Please fix the errors below" with no indication of which fields failed. The user has to hunt.
Edge cases
aria-describedbyconnects the error message to the field.aria-invalidflags the field state. Use both.- Form-level summaries are useful for long forms — they let keyboard users jump to the first error. Pair with field-level errors.
- Inline validation timing. Show errors on blur or submit, not on every keystroke — too-eager validation announces errors before the user has finished typing.
- HTML validation (
required,type="email") provides browser- native error UI, but the browser's text is locale-bound and may not be customisable. Custom validation is usually better, but attribute-based validation is a reasonable starting point. - Live regions for async validation errors should use
aria-live="polite"so the announcement waits for natural pauses.
How Jeikin handles this
axe-core flags aria-invalid without an associated text message,
and fields with custom error styling but no aria-describedby. The
dashboard maps each finding to WCAG 3.3.1. The harder question —
"is the error text understandable?" — is captured as a reviewer note.