Tutorial
How to make form errors accessible
2 min read
In short
A form error has to be named in text (3.3.1), tied to its field programmatically (aria-describedby plus aria-invalid), and say how to get it right (3.3.3). If it appears only after submission it also has to be announced: role="alert", or move focus into an error summary (4.1.3).
At a glance
Write the error as text
Colour and borders are not enough. The error needs a sentence that names it.
Tie it to the field
Point aria-describedby at the message id and set aria-invalid="true" on the field.
Say the way out
Write what is expected, with an example: „Example: name@company.com“.
Make sure it is announced
For errors that appear later, use role="alert" or move focus into the error summary.
Forms are where accessibility turns into revenue: someone who cannot find the error does not order. And this is exactly where most implementations fail, because the error message exists for eyes only.
What goes wrong here
<form>
<label for="mail">E-Mail</label>
<input id="mail" name="mail" class="input-error">
<!-- Fehler nur farblich und optisch, nicht programmatisch:
- keine Verbindung zum Feld
- keine Rolle, also keine Ansage
- "ungueltig" sagt nicht, was erwartet wird -->
<span class="error-text">Ungueltig</span>
<button type="submit">Weiter</button>
</form>- The message is not tied to the field: someone tabbing into it hears nothing about it.
- „Invalid“ does not say what is expected (3.3.3 asks for a suggestion when one is known).
- The message appears silently: with no live semantics and no focus change, nobody who is not looking notices (4.1.3).
The fix on a single field
<form novalidate>
<label for="mail">E-Mail</label>
<input
id="mail"
name="mail"
type="email"
autocomplete="email"
aria-invalid="true"
aria-describedby="mail-error"
>
<!-- Mit dem Feld verbunden (aria-describedby), als Text identifiziert
und mit einem konkreten Hinweis, wie es richtig geht -->
<p id="mail-error" class="error-text">
E-Mail-Adresse fehlt das @-Zeichen. Beispiel: name@firma.de
</p>
<button type="submit">Weiter</button>
</form>Several errors at once
<!-- Bei mehreren Fehlern: eine Zusammenfassung oben, fokussiert nach
dem Absenden. Jeder Eintrag springt zum betroffenen Feld. -->
<div role="alert" tabindex="-1" id="error-summary">
<h2>2 Angaben fehlen</h2>
<ul>
<li><a href="#mail">E-Mail-Adresse fehlt das @-Zeichen</a></li>
<li><a href="#plz">Postleitzahl braucht 5 Ziffern</a></li>
</ul>
</div>
<script>
// Nach dem Absenden: Fokus in die Zusammenfassung, damit die Ansage
// ankommt und die Tastatur direkt am Fehler steht.
document.getElementById("error-summary").focus();
</script>After submitting a long form, the summary is the most reliable route: it states how many errors there are, names each one, and takes focus to the right place in one click. That helps everyone, not only screen-reader users.
Common additional mistakes
- Placeholder as a label: it disappears while typing and is not a label (use a real label element).
- Error colour with no second cue: red alone violates 1.4.1 (Use of Colour).
- Messages that vanish and reappear on every keystroke: that produces one announcement per key. Validate on blur or on submit.
- An aria-live container inserted together with its text: often nothing is heard. The container has to exist first and only be filled.
Testing
- Submit the form empty and navigate to the first error with the keyboard only.
- Check with a screen reader: is the error announced? Is it repeated when the field takes focus?
- Zoom to 200 percent: does the message stay visible next to its field?
Related WCAG criteria
Frequently asked questions
- Is the browser's built-in HTML validation enough?
- It is a good starting point, but its messages are barely styleable, worded differently per browser, and disappear by themselves. For a reliable result, validate yourself and write the message into the markup.
- When role="alert" and when a focus move?
- role="alert" suits single short messages that must arrive immediately. For several errors after submission, moving focus into a summary is more reliable, because it also takes the operating position along.
- Does every error message need a suggestion?
- 3.3.3 asks for one when it is known and would not compromise security. For a format error it is known („Example: name@company.com“); for a login password it is not, and there it would be harmful.
Request a free scan
Tell us your domain - we run a free initial scan and show you the most important barriers.