Purpose
Accessible form validation ensures that users of all abilities understand which fields have errors, what the error is, and how to correct it—without relying solely on color.
Usage Guidance
- Display errors inline, adjacent to the field
- Summarize all errors at the top of the form for long forms
- Never use color alone to indicate errors
- Show errors after user interaction (not on page load for required fields)
- Provide corrective guidance, not just “Field is invalid”
Accessibility Considerations
- Associate error messages with fields using
aria-describedby - Mark invalid fields with
aria-invalid="true" - Use
role="alert"on dynamically injected error summaries - Use
aria-live="polite"for inline errors that appear after validation
Keyboard Support
Form validation follows standard form keyboard behavior. After validation, move focus to the first invalid field or the error summary.
Screen Reader Behavior
When aria-invalid="true" is set, screen readers announce “invalid entry” when focusing the field. aria-describedby ensures the error message is read when the field receives focus.
ARIA Requirements
aria-invalid="true"on invalid fieldsaria-describedby="error-id"on each invalid field, referencing its error messagerole="alert"on dynamically injected error summaries
Common Mistakes
- Using only red border/text color to indicate errors
- Not associating error text with the field via
aria-describedby - Not setting
aria-invalid="true"on the field - Moving focus to an error summary without giving it
tabindex="-1"first
Live Example
Code Example
<div class="form-group">
<label for="email">
Email Address
<span aria-hidden="true">*</span>
<span class="visually-hidden">(required)</span>
</label>
<input
id="email"
type="email"
aria-required="true"
aria-invalid="false"
aria-describedby="email-error"
>
<p id="email-error" role="alert" hidden>
Please enter a valid email address (e.g., name@example.com).
</p>
</div>
function validateField(input) {
var isValid = input.checkValidity();
var errorEl = document.getElementById(input.getAttribute('aria-describedby'));
input.setAttribute('aria-invalid', String(!isValid));
errorEl.hidden = isValid;
}