Form submission errors are clearly communicated
Why it matters
A form that displays validation errors as inline red text — but does not announce them to assistive technology — leaves screen reader users in a silent loop: they submit the form, receive no feedback, and submit again, never understanding why their submission fails. WCAG 2.2 SC 3.3.1 (Error Identification) requires error fields to be identified programmatically. SC 3.3.3 (Error Suggestion) requires that suggestions for correction be provided when the format is known. SC 4.1.3 (Status Messages) requires status messages to be programmatically determinable. Section 508 2018 Refresh 502.3.14 covers status change announcements. The aria-describedby link between an error message and its input is the mechanism that allows a screen reader to read the error when the user focuses the invalid field.
Severity rationale
High because inaccessible error communication completely prevents screen reader users from diagnosing and correcting form submission failures.
Remediation
Implement a two-part error communication strategy: an aria-live error summary that announces on submission failure, and per-field aria-describedby links that surface the error when the field receives focus.
const ContactForm = () => {
const [errors, setErrors] = useState<Record<string, string>>({});
const summaryRef = useRef<HTMLDivElement>(null);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const newErrors: Record<string, string> = {};
if (!email) newErrors.email = 'Email address is required.';
if (!message) newErrors.message = 'Message cannot be empty.';
setErrors(newErrors);
if (Object.keys(newErrors).length > 0) {
// Move focus to summary so screen reader announces it
summaryRef.current?.focus();
}
};
return (
<form onSubmit={handleSubmit} noValidate>
{Object.keys(errors).length > 0 && (
<div
ref={summaryRef}
role="alert"
aria-live="assertive"
tabIndex={-1}
>
<h2>Please fix {Object.keys(errors).length} error(s):</h2>
<ul>
{Object.entries(errors).map(([field, msg]) => (
<li key={field}><a href={`#${field}`}>{msg}</a></li>
))}
</ul>
</div>
)}
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
aria-required="true"
aria-invalid={!!errors.email}
aria-describedby={errors.email ? 'email-error' : undefined}
/>
{errors.email && (
<p id="email-error" role="alert">{errors.email}</p>
)}
<button type="submit">Send</button>
</form>
);
};
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Accessibility Basics Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- wcag:2.2 · 3.3.1 — Error Identification
- wcag:2.2 · 3.3.3 — Error Suggestion
- wcag:2.2 · 4.1.3 — Status Messages
- section-508:2018-refresh · 502.3.14 — Event Notification
Taxons
History
- 2026-04-18·v1.0.0·Initial import from accessibility-basics·automated