Road sign with a left-pointing arrow symbolizing direction or choice.

Image description: Road sign with a left-pointing arrow symbolizing direction or choice.

Accessible error messages

Accessibility engineering

Accessible error messages: The complete guide

Every form field you create, every validation you trigger, every failure state you display — these are moments where digital products either include or exclude millions of people. Here’s how to get every one of them right.

18 min read WCAG 2.2 AA AIOPSGROUP Editorial

The hidden cost of unhelpful errors

You have probably seen it: a form that tells you “Invalid input” after you’ve carefully typed your phone number. A checkout process that marks a field red but offers no explanation. An error message that uses cryptic codes understood only by the developer who wrote it at 11pm on a Friday.

These aren’t minor UX inconveniences. For the 1.3 billion people worldwide who live with some form of disability, poorly crafted error messages can make a digital product completely unusable. For screen reader users, an error message that only changes color is invisible. For users with cognitive disabilities, a vague one-liner like “Something went wrong” is paralysing. For someone relying on voice control, a form error that steals focus unpredictably breaks the entire workflow.

95.9% of homepage tests fail at least one WCAG criterion (WebAIM 2024)
1 in 4 US adults live with a disability affecting digital access
$13 billion+ lost annually worldwide due to inaccessible websites (Web Standards Commission)

Accessible error messages are not about adding ARIA attributes as an afterthought. They require intentional language, appropriate DOM structure, visual and non-visual signalling, and a deep respect for the diversity of your users. This guide walks through every dimension of getting them right — from WCAG criteria to copywriting principles to live code patterns.

Scope of this article

We focus on client-side and server-side validation errors in web interfaces, though most principles apply equally to native mobile apps, kiosk terminals, and voice interfaces. References are to WCAG 2.2 AA unless otherwise noted.


What the standard actually demands

WCAG 2.2, published in October 2023, is the current benchmark for web accessibility and the reference point for most legal frameworks — including the EU Web Accessibility Directive, the UK Equality Act, and the US ADA. Several success criteria apply directly to error messages. Understanding the letter of each one is essential before you can go beyond them.

WCAG 2.2 success criteria relevant to error messages
Criterion Level What it requires For error messages
1.3.1 Info and relationships A Convey structure and relationships through semantics, not only through presentation. An error state shown only via colour fails. The relationship between a field and its error must be programmatically determinable — use <label>, aria-invalid="true", and aria-describedby to associate the error text with the input.
1.4.1 Use of colour A Don’t use colour as the only visual means of conveying information. Red borders alone are insufficient. Add an icon, text label, or pattern.
1.4.3 Contrast (minimum) AA Text must have at least 4.5:1 contrast ratio (3:1 for large text). Error text in light red (#f87171) on white achieves only ~2.93:1 — far below the required 4.5:1. Use deeper tones: #b91c1c on white delivers ~7.1:1 and passes comfortably.
2.4.3 Focus order A Focus order must preserve meaning and operability. Mismanaged focus after a failed submission can break the logical sequence (e.g. focus lands after the error, making it unreachable). Moving focus to an error summary on submission failure is a recommended technique — primarily serving SC 3.3.1 and 3.3.2 — that also keeps the focus order coherent under 2.4.3.
3.3.1 Error identification A If an input error is detected, the item is identified and the error is described in text. The error must be described in text — not just visually indicated.
3.3.2 Labels or instructions A Provide labels or instructions when content requires user input. Format hints (e.g. “DD/MM/YYYY”) must be present before submission, not only on error.
3.3.3 Error suggestion AA If an error is detected and suggestions are known, provide them. “Invalid date” is insufficient. “Enter a date in DD/MM/YYYY format, e.g. 23/03/2026” is correct.
3.3.4 Error Prevention AA For legal/financial/data submissions, provide review, confirm, or reversal. Allow users to review and correct before final submission.
4.1.3 Status messages AA Status messages can be programmatically determined through role or property without receiving focus. Use role="alert", role="status", or aria-live so AT users receive the message.

What makes a good error message

A well-formed error message has four non-negotiable components. Each one serves a distinct purpose — remove any one of them, and you degrade the experience for some portion of your users.

Annotated error message
Error icon (visual redundancy) An icon alongside the red border ensures the error is perceptible without relying on colour alone. Satisfies 1.4.1. The icon must be aria-hidden if the text already conveys the meaning.
Error border on the field Red border (≥2px) visually associates the message with the input. Combined with aria-invalid=”true” on the input, this satisfies 1.3.1.
Descriptive error text (plain language) The message explains what is wrong and how to fix it. “Enter a complete email address” + “for example, [email protected]” satisfies 3.3.1 and 3.3.3.
Programmatic association (aria-describedby) aria-describedby links the error text to the field. When a screen reader user focuses the input, they hear the label + error description. Required for 1.3.1 and 4.1.3.

The language framework: Six rules for error copy

Error messages are a form of UX writing. They are not log output. They are not developer notes. They are human communication under stress — written for someone who just failed at something and needs to succeed.

🎯

1. Be specific

Tell the user exactly what is wrong. “Invalid” tells them nothing. “Password must be at least 8 characters” tells them everything.

🔧

2. Be actionable

The message should imply or directly state how to fix the error. Include format examples where the format is non-obvious.

🚫

3. Avoid blame

Never say “you entered”, “your input”, or “you failed”. Prefer passive constructions: “The email address entered is incomplete.”

🧩

4. Use plain language

Write at a reading age of around 11. Avoid jargon, technical codes, and passive-aggressive phrasing like “please try again.”

5. Time it correctly

Show inline errors on blur (when the user leaves the field), not on every keystroke. Show summary errors only after submission attempt.

🌐

6. Consider the context

A payment form error deserves more reassurance than a search filter. Match tone and detail to the stakes of the task.


Real Error Messages: Before & After

The gap between an inaccessible and an accessible error message is often just a few words and two attributes. These comparisons show exactly what changes — and why each change matters.

Required field validation

✕ Inaccessible
This field is required.

Problems: Doesn’t identify which field. Provides no action. Often surfaced only with colour change (fails 1.4.1). No role="alert" means screen readers won’t announce it.

✓ Accessible
Enter your date of birth. This field is required to confirm your eligibility.

Why it works: Names the field. Explains why it’s needed. Linked to the input via aria-describedby. Text contrast ≥ 4.5:1. Screen readers announce it on submit via role="alert".

Format validation (date)

✕ Inaccessible
Invalid date format.

Problems: User doesn’t know what format is expected. Tells them what’s wrong, but not how to fix it. Fails 3.3.3 (Error Suggestion). No example provided.

✓ Accessible
Enter the date in DD/MM/YYYY format. For example: 23/03/2026

Why it works: Specifies the required format. Gives a concrete example (satisfies 3.3.3). Concise and plain. Would be announced by screen readers immediately on field blur.

Password validation

✕ Inaccessible
Password too weak.

Problems: “Weak” is subjective and provides no fix path. Typically shown with a red strength bar — which is colour-only feedback (fails 1.4.1). No relationship between bar state and AT output.

✓ Accessible
Password must be at least 8 characters and include one uppercase letter and one number.

Why it works: Lists each requirement. Users can scan and address each gap. The strength indicator supplements this text and uses both colour AND text label (“Weak / Strong”). No information carried by colour alone.

Server / system error

✕ Inaccessible
Error 500. Something went wrong.

Problems: Technical code is meaningless to most users. “Something went wrong” provides no action path. Injected into DOM without live region — silent for screen readers. No recovery suggestion.

✓ Accessible
We couldn’t save your changes. Please try again, or contact support if the problem continues.

Why it works: Human language. Confirms what failed. Gives two clear recovery paths. Injected into an aria-live="assertive" region so screen readers announce it immediately. Focus moved to the message.

The best error message is one that prevents the error from happening in the first place. The second-best error message is one that makes recovery trivially obvious.


Error patterns & when to use them

Different error scenarios call for different interaction patterns. Choosing the wrong container or announcement mechanism is one of the most common accessibility failures in forms.

Error pattern comparison
Pattern Best for ARIA implementation Focus behaviour Required
Inline field error Immediate field-level validation (on blur) aria-invalid="true" + aria-describedby No focus movement. Error heard on next focus of field. Required
Error summary banner Multi-field form submission errors role="alert" or aria-live="assertive" Move focus to the summary heading on submission. Required for forms >3 fields
Toast / snackbar notification Non-form errors (save failed, network issue) role="alert" or aria-live="assertive" Do NOT move focus. Auto-dismiss after ≥5 seconds (or never). Recommended
Modal dialog error Destructive action confirmation, critical errors role="dialog" + aria-modal="true" + aria-labelledby Move focus to first interactive element inside dialog. For critical/irreversible errors
Page-level alert region Server errors returned after page reload role="alert" at top of <main> Should be first focusable element after skip link. Required if present on load
Status polite message Low-urgency feedback (auto-saved, optional field skipped) aria-live="polite" + role="status" No focus movement. Announced after current speech finishes. Optional / context-dependent

The dual-layer approach for multi-field forms

For forms with three or more fields, a single pattern is insufficient. The Government Digital Service (GDS) and the ARIA Authoring Practices Guide both recommend a dual-layer system: an error summary at the top of the form, plus inline error messages beside each affected field.

Dual-layer pattern: How it works

On submission with errors: (1) Inject an error summary container at the top of the form with a heading like “There are 3 errors. Fix these to continue.” and links to each erroneous field. (2) Move keyboard focus to that summary heading. (3) Each link in the summary jumps to the corresponding field. (4) Each field displays its own inline error message linked via aria-describedby. Screen reader users hear both layers; sighted users see both layers. Nobody is left behind.


Code patterns that work

Understanding the theory is half the battle. Below are production-ready patterns for the most common scenarios, annotated with the WCAG criteria each attribute satisfies.

Inline field validation

HTML
<!-- The label is always present and always linked -->
<div class="field-group">
  <label for="email">
    Email address
    <span class="required-indicator" aria-label="required"> *</span>
  </label>

  <input
    type="email"
    id="email"
    name="email"
    autocomplete="email"
    aria-required="true"
    aria-invalid="true"     <!-- set when invalid -->
    aria-describedby="email-hint email-error"
  />

  <!-- Hint text always shown (WCAG 3.3.2) -->
  <p id="email-hint" class="field-hint">
    We'll send your confirmation here.
  </p>

  <!-- Error message (shown only on error) -->
  <p
    id="email-error"
    class="field-error"
    role="alert"
    aria-live="assertive"
  >
    <!-- inject error text here -->
    Enter a complete email address — for example, [email protected]
  </p>
</div>

Error summary (multi-field forms)

HTML
<!-- Inject this above the form on submission, then focus #error-summary -->
<div
  id="error-summary"
  role="alert"
  aria-labelledby="error-summary-title"
  tabindex="-1"   <!-- allows programmatic focus -->
  class="error-summary"
>
  <h2 id="error-summary-title">
    There are 2 errors. Fix these to continue.
  </h2>
  <ul>
    <li><a href="#email">Email address: enter a complete email</a></li>
    <li><a href="#dob">Date of birth: use DD/MM/YYYY format</a></li>
  </ul>
</div>

<!-- JavaScript: move focus to summary after injection -->
<script>
  const summary = document.getElementById('error-summary');
  summary.focus(); // fires after DOM update
</script>

Dynamic / AJAX errors (no page reload)

When errors are returned asynchronously — from an API call, for example — you can’t rely on page load to surface them. The ARIA live region pattern is essential here.

JS
// Set up the live region once on page load (empty, hidden)
// <div id="live-error" role="alert" aria-live="assertive" aria-atomic="true"></div>

async function submitForm(data) {
  try {
    const res = await fetch('/api/save', { method: 'POST', body: data });
    if (!res.ok) throw new Error(await res.text());
    announceStatus('Your changes have been saved.', 'polite');
  } catch (err) {
    announceStatus(
      'We couldn\'t save your changes. Try again or contact support.',
      'assertive'
    );
  }
}

function announceStatus(message, urgency = 'polite') {
  const region = document.getElementById('live-error');
  region.setAttribute('aria-live', urgency);
  // Clear first to re-trigger announcement if same message
  region.textContent = '';
  requestAnimationFrame(() => {
    region.textContent = message;
  });
}
The empty-then-fill trick

Screen readers only announce content that changes in a live region. If you inject the same error message twice in a row, some ATs won’t re-announce it. The workaround: clear the region to an empty string, then populate it in a requestAnimationFrame callback. This forces the DOM mutation the AT is listening for.


The error accessibility audit checklist

Use this checklist during design review, code review, and QA. It covers all Level A and Level AA WCAG 2.2 criteria relevant to error states.

Visual & content

Visual & content
  • Error is communicated through text, not colour alone (WCAG 1.4.1)
  • Error text has ≥ 4.5:1 contrast ratio against its background (WCAG 1.4.3)
  • An icon or visual marker supplements the colour change
  • Error message names the field or is physically adjacent to it
  • Error message explains what is wrong (not just “invalid”)
  • Error message includes how to fix the error (WCAG 3.3.3)
  • Format examples are provided for date, phone, postcode, and similar fields
  • Language is plain, non-technical, and non-blame-assigning
  • Error text does not disappear until the error is resolved
  • Format hints (e.g. “DD/MM/YYYY”) are shown before submission, not only on error

Programmatic & AT

Programmatic & assistive technology
  • aria-invalid="true" is set on the erroneous input
  • Error message element is linked via aria-describedby on the input
  • Error container uses role="alert" or aria-live="assertive"
  • Error region is not empty in the DOM before errors exist (pre-populated empty container)
  • Error summary is injected and focused programmatically on form submission failure
  • Error summary links navigate to the corresponding form field
  • Screen reader testing passes on NVDA/Firefox and VoiceOver/Safari
  • Page title updates to reflect error state on full-page form submissions
  • Status messages use role="status" with aria-live="polite" for non-critical feedback

Focus & keyboard

Focus management & keyboard
  • Focus moves to the error summary (or first error field) after failed submission
  • Focus indicator is clearly visible on all error-state interactive elements (WCAG 2.4.11)
  • Modal error dialogs trap focus within the dialog
  • Dismissing an error (e.g. closing a toast) returns focus to a logical position
  • No error interaction requires a pointing device
  • Timeout errors give adequate warning and time to extend session (WCAG 2.2.1)
Beyond compliance: AAA aspirations

WCAG 3.3.6 (Error Prevention — All) asks you to let users check, confirm, and reverse all submissions — not just financial ones. While this is AAA and not legally required in most contexts, it significantly reduces error-induced stress for users with cognitive disabilities. Consider it the gold standard worth pursuing.


How we got here: A brief timeline

1999
WCAG 1.0 published Web Content Accessibility Guidelines arrive. Accessibility of form feedback is addressed loosely under Priority 2 checkpoints. No specific error message criteria.
2008
WCAG 2.0 — error criteria formalised Success Criteria 3.3.1–3.3.4 introduced. For the first time, standards explicitly require text-based error identification and error suggestions. AA compliance becomes the legal benchmark.
2018
WCAG 2.1 — cognitive & mobile focus New criteria improve support for users with cognitive disabilities. SC 1.3.5 (Identify Input Purpose) requires autocomplete on personal data fields, reducing error rate at source.
2019
ARIA 1.1 — live regions stabilised ARIA authoring practices formalise role="alert" and aria-live patterns. Consistent browser and AT support finally achievable for dynamic error announcements.
2021
EU Web accessibility directive enforcement Public sector websites in EU member states face mandatory WCAG 2.1 AA compliance. Error messages become a primary audit target for national oversight bodies.
2023
WCAG 2.2 — focus & cognitive improvements SC 2.4.11 (Focus appearance) tightens focus indicator requirements on interactive elements — including fields in error state. SC 3.3.7 (Redundant Entry) reduces cognitive load in multi-step forms.
2026
European Accessibility Act (EAA) takes effect Private sector products and services must comply with EN 301 549 (which references WCAG 2.1 AA). E-commerce, banking, transport, and e-books are all in scope. Accessible error messages are now a legal requirement for most commercial web applications in Europe.

Error messages as a mirror of your product’s values

The error message is one of the most revealing moments in any digital experience. It arrives precisely when a user is under stress — when they’ve made a mistake, or when something beyond their control has gone wrong. What you do in that moment says everything about how seriously you take inclusion.

A red border with no text is not an error message. A code dump is not an error message. A vague “something went wrong” is not an error message. An accessible error message is a piece of clear, kind, actionable human communication that works for everyone — including the 26% of users who experience some form of disability, the 15% who rely on keyboard navigation, and the 100% of users who will encounter an error at some point.

Accessibility is not a feature. It is a quality attribute of every feature you ship — and error messages are where that quality is tested under the worst conditions.

The good news is that accessible error messages require very little extra effort when incorporated from the beginning. The ARIA attributes are minimal. The copy guidelines are clear. The patterns are well-established. What they require is intention — a deliberate decision to test with assistive technologies, to write for humans instead of systems, and to treat every failure state as an opportunity to earn trust.

At AIOPSGROUP, a valantic company, we build digital products that work for everyone. Accessibility engineering is embedded in our design system, our code reviews, and our QA process — not bolted on at the end. If your team needs help auditing, implementing, or building an accessible design system from the ground up, we’d be glad to help.