Accessible form structure
Write accessible error messages
Identify the field, explain the problem, preserve entered values, and make errors available without relying only on color.
A good error message does three things. It names the field, explains what’s wrong, and says how to fix it.
“Email is invalid” fails on the third point. What should I type instead? “Enter an email address in the format [email protected]” tells me exactly what to do.
Connect the message to the field
Put the message right next to the field and wire it up:
<label for="email">Email address</label>
<input
id="email"
name="email"
type="email"
value="ada@"
aria-invalid="true"
aria-describedby="email-error"
>
<p id="email-error">Enter an email address in the format [email protected].</p>
aria-invalid="true" tells assistive technology the field is currently wrong. aria-describedby points at the message, so a screen reader announces it together with the label when the field gets focus.
Notice the value="ada@". The form comes back with what the person typed, so they can fix it instead of starting over.
Don’t rely on color alone
A red border is the most common way to mark an error. It’s also invisible to many people: those with color vision deficiency, those on a bright screen outdoors, and everyone using a screen reader.
The visible text message solves this. Keep the red border if you like, but make the text carry the meaning. An icon next to the message helps too.
Several errors at once
When a long form comes back with more than one problem, add a summary at the top:
<div role="alert" tabindex="-1">
<h2>There are 2 problems</h2>
<a href="#email">Enter a complete email address</a>
</div>
role="alert" makes screen readers announce the content as soon as it appears. tabindex="-1" lets your script move focus to it. Each link jumps to the invalid field, so the person can work through the list.
Keep what was valid
Preserve every valid value when you return the form. If the email failed, the name and the message the person already typed must still be there. Re-entering unrelated fields is a punishment, not validation.
There is one exception. Never echo a password back into the page, even a wrong one. Leave password fields empty.
Escape what you echo
The value you put back into the page came from the request. Escape it before rendering it into HTML. Otherwise a value like <script> submitted in the name field runs when the form is redrawn.
Try this: turn on grayscale in your operating system, zoom the page to 200%, and submit the form with a bad email. You should still find the problem and the field it belongs to. If you have a screen reader available, do it once more with your eyes closed.
Lesson completed