Form errors that appear only as a red border or generic 'Invalid' message leave screen reader users without actionable feedback — the element's invalid state is not announced, and there is nothing to explain what went wrong or how to fix it. WCAG 2.2 SC 3.3.1 (Error Identification) and SC 3.3.2 (Labels or Instructions) are both Level A requirements. Poor error UX also measurably increases form abandonment rates for all users.
Medium because form errors that are not announced or explained prevent screen reader users from correcting and submitting forms, violating WCAG 2.2 SC 3.3.1 at Level A — a functional blocker for form completion.
Associate error messages with their inputs using aria-describedby and aria-invalid, and use role="alert" so the message is announced immediately.
const emailError = validate(email)
<div>
<label htmlFor="email">Email address</label>
<input
id="email"
type="email"
aria-invalid={!!emailError}
aria-describedby={emailError ? 'email-err' : undefined}
/>
{emailError && (
<p id="email-err" role="alert" className="text-sm text-red-600">
{emailError}
{/* Good: "Enter a valid email (e.g., name@example.com)" */}
{/* Bad: "Invalid" */}
</p>
)}
</div>
Search for aria-describedby usage in forms — every input with possible validation errors should have one. Also check error string literals: any message under five words is likely too vague to satisfy WCAG 2.2 SC 3.3.2.
ID: accessibility-wcag.operable.error-identification
Severity: medium
What to look for: Enumerate every relevant item. Submit a form with invalid data. Check that errors are: 1) identified in text (not just color or icon), 2) associated with the field via aria-describedby, and 3) describe the issue and how to fix it.
Pass criteria: At least 1 of the following conditions is met. Form errors are announced, associated with inputs, and describe the problem in plain language.
Fail criteria: Errors are displayed only via color/icon, or the error message is vague (e.g., "Invalid").
Skip (N/A) when: The project has no forms.
Detail on fail: Example: "Form shows red border on invalid email field with no error text. Error message says 'Invalid input' without explaining what to fix"
Remediation: Associate error messages with inputs:
<div>
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
aria-describedby={error ? 'email-error' : undefined}
aria-invalid={!!error}
/>
{error && (
<span id="email-error" role="alert" className="text-red-600">
Please enter a valid email address (e.g., user@example.com)
</span>
)}
</div>