Accessible Form Labels and Error Messages: Fixing Checkout Issues
Short answer: Give every field a visible, programmatically associated label, say which fields are required, describe errors in text rather than color alone, link each error to its field with aria-describedby, and announce submit-level errors through a live region. These changes address WCAG 1.3.1, 3.3.1, 3.3.2 and 4.1.2.
Checkout forms are where accessibility problems cost a business the most, because a shopper who cannot complete the form cannot buy. Form labels and error messages are also among the most common problems found in automated and manual audits of online stores.
This guide covers four recurring problems, shows the HTML before and after, and explains how to test your own forms. It is general information, not legal advice. For questions about legal exposure, talk to an attorney.
The four problems, and the WCAG criteria behind them
| Problem | What a user experiences | WCAG 2.1 criterion |
|---|---|---|
| Input has no label, or the label is not connected to it | A screen reader says "edit text" with no hint what to type | 1.3.1 Info and Relationships, 4.1.2 Name, Role, Value |
| Placeholder used as the only label | The hint vanishes once typing starts; it is often low contrast | 3.3.2 Labels or Instructions, 1.3.1 |
| Required status or format not stated | Users learn a field was required only after failing | 3.3.2 Labels or Instructions |
| Error shown only in red, or not announced | Users who cannot see color, or who use a screen reader, never learn what went wrong | 3.3.1 Error Identification, 4.1.2 |
You can read the criteria themselves at the W3C WCAG 2.1 specification. Our fix guides cover 1.3.1 Info and Relationships, 3.3.2 Labels or Instructions and 4.1.2 Name, Role, Value.
Fix 1: a real label for every field
A visible label connected to its input is the most reliable fix. The for attribute on the label must match the id on the input.
Before: the text sits next to the field, but nothing connects them.
<div>Email address</div>
<input type="text" name="email">
After: the label is programmatically associated, and clicking the label focuses the field.
<label for="email">Email address</label>
<input type="email" id="email" name="email" autocomplete="email">
A few notes:
- Use the correct
type(email,tel) so mobile keyboards and browsers help the user. autocompletevalues such asemail,given-name,postal-codeandcc-numberhelp many users and relate to WCAG 1.3.5 Identify Input Purpose, which is part of 2.1 AA.- A
nameattribute is not a label. Neither istitleas a first choice. - Do not rely on
aria-labelwhen you can show a visible label. Visible text helps everyone, and it keeps the visible and accessible names matching.
Fix 2: do not use the placeholder as the label
Placeholder text disappears when the user types, so people with memory or attention difficulties lose the prompt. Placeholders are also commonly styled in light gray that fails contrast. Browser and screen reader handling of placeholders as names has varied, so do not depend on it.
Before:
<input type="text" name="postcode" placeholder="Postal code">
After: keep a visible label, and use the placeholder only for an optional example.
<label for="postcode">Postal code</label>
<input type="text" id="postcode" name="postcode"
autocomplete="postal-code" placeholder="e.g. 12345">
If your design uses a "floating label" that moves above the field on focus, check that the label is a real <label>, stays visible while typing, and has enough contrast. See our color contrast guide and WCAG 1.4.3.
Fix 3: say what is required, in text
Many forms mark required fields with a red asterisk and nothing else. Color alone does not carry the message, and a bare asterisk may mean nothing to some users.
Before:
<label for="phone">Phone <span style="color:red">*</span></label>
<input type="tel" id="phone" name="phone">
After: explain the convention once at the top of the form, mark the field in text, and use the required attribute.
<p>Fields marked "required" must be completed.</p>
<label for="phone">Phone (required)</label>
<input type="tel" id="phone" name="phone" autocomplete="tel" required>
Browsers expose the required attribute to assistive technology, so screen readers can announce it. If you use aria-required="true" on a custom control, keep the visible text too. Also state formats up front when they matter, for example "Date (MM/DD/YYYY)", rather than revealing them only after an error.
One note on the native required attribute: the built-in browser validation bubbles are inconsistent across browsers and assistive technologies. Many teams add novalidate to the form and handle validation themselves, as shown below. If you do that, you take on the responsibility for making errors accessible.
Fix 4: error messages in text, linked to the field
WCAG 3.3.1 asks that when an error is detected automatically, the item in error is identified and the error is described to the user in text. A red border does not meet that on its own.
Before: color only, nothing for a screen reader.
<label for="zip">ZIP code</label>
<input type="text" id="zip" name="zip" style="border:2px solid red">
After: a text message, associated with the field using aria-describedby, with aria-invalid set.
<label for="zip">ZIP code</label>
<input type="text" id="zip" name="zip"
aria-invalid="true"
aria-describedby="zip-error">
<p id="zip-error" class="error">
Error: Enter a 5-digit ZIP code, for example 90210.
</p>
Why this works:
aria-describedbymakes the screen reader read the message when the field receives focus, after its label.- The word "Error" and a specific instruction mean the message makes sense without color.
aria-invalid="true"tells assistive technology the value is not accepted. Set it only after validation, and remove it when the problem is fixed.- If you also want an icon or red styling, keep them as extras. Make sure the text and icon meet contrast requirements.
Write messages that help: "Enter a valid email address, such as [email protected]" is better than "Invalid input." Where you can suggest a correction, do. WCAG 3.3.3 Error Suggestion is a Level AA criterion that asks for this where it is known, and it pairs naturally with 3.3.1.
Fix 5: announce submit errors with a live region
When a user presses "Place order" and several fields fail, sighted users see red text appear. A screen reader user may hear nothing, because focus has not moved. Two common patterns solve this, and you can use them together.
Pattern A: a live region that summarizes the problem. The container must exist in the page before the message is inserted.
<div id="form-status" role="alert"></div>
<script>
function showSummary(count) {
document.getElementById("form-status").textContent =
count + " fields need your attention. Please review the errors below.";
}
</script>
role="alert" is assertive and interrupts speech, so reserve it for submit failures. For less urgent updates, role="status" is polite and waits for a pause.
Pattern B: an error summary that receives focus. Move focus to a heading or container that lists the errors, with links to each field.
<div id="error-summary" tabindex="-1">
<h2>2 problems with your order</h2>
<ul>
<li><a href="#email">Enter an email address</a></li>
<li><a href="#zip">Enter a 5-digit ZIP code</a></li>
</ul>
</div>
<script>
document.getElementById("error-summary").focus();
</script>
Either pattern is acceptable. What matters is that a user who cannot see the screen is told that the submit failed and where to look. WCAG 4.1.3 Status Messages, part of 2.1 AA, covers messages that appear without taking focus.
Two cautions. Do not inject role="alert" on the error text for every keystroke; it becomes noisy. And do not remove the focus outline from controls; see WCAG 2.4.7 Focus Visible.
How to test your forms
Keyboard test (about five minutes)
- Reload the checkout and put the mouse aside.
- Press Tab through every field. Is the order logical, and is focus always visible?
- Submit the form empty. Can you find out, without a mouse, which fields failed?
- Correct one error at a time. Does the message go away, and does focus stay predictable?
Our five-minute keyboard test walks through this in more detail, and WCAG 2.1.1 Keyboard covers the underlying requirement.
Screen reader test
Use VoiceOver on Mac or iPhone, or NVDA on Windows (free). Tab to each field and listen. You should hear the label, the type of control, "required" where relevant, and any error description. Then submit with errors and check that you hear a summary or land on one. Our screen reader testing basics guide covers setup. Results vary slightly between screen reader and browser pairs, so test at least one combination, and more if you can.
Quick automated and manual checks
- Automated tools catch missing labels and some association errors. They cannot judge whether an error message is helpful or whether a live region is announced. Treat them as a first pass.
- Inspect the page: does every input have an accessible name in the browser's accessibility tree?
- Zoom to 200% and confirm labels and errors stay visible and do not overlap.
Where this fits in the bigger picture
Form labeling is one part of an accessible checkout. For the wider list, see accessible checkout fixes and the WCAG 2.1 AA checklist. If you received a demand letter that cites forms, read what to do in the first two weeks and speak with an attorney about your situation. Fixing these issues improves usability, but no single change guarantees any legal outcome.
Keep a dated record of what you tested and fixed. When you are ready to see where your own site stands, run a free scan.
Frequently asked questions
Is a placeholder enough as a label?
Generally no. A placeholder disappears as soon as someone types, is often low contrast, and is handled inconsistently by assistive technology. Use a visible <label> and keep the placeholder, if any, for an example value.
Can I show errors only in red?
Color alone is not enough, because some users cannot perceive it. Describe the error in text, identify the field in error, and treat color or icons as extras. This is what WCAG 3.3.1 asks for.
Should I use aria-label instead of a visible label?
Prefer a visible label connected with for and id. Use aria-label or aria-labelledby only when a visible label is not practical, such as an icon-only search button. Keep the accessible name consistent with any visible text.
Do I need role="alert" on every error message?
No. Link each field's error with aria-describedby, and use one live region or a focused error summary to announce that the submit failed. Marking every message as an alert can flood a screen reader user with interruptions.
Will fixing labels and errors protect me from a lawsuit?
Nobody can promise that. These fixes address commonly cited barriers and make the form easier to use, but legal outcomes depend on many facts and courts disagree on several questions. Ask an attorney about your specific situation.
Related
- Accessible checkout: the fixes that matter most for online stores
- Screen Reader Testing for Business Owners: VoiceOver and NVDA Basics
- A 5-Minute Keyboard Accessibility Test for Your Online Store
- WCAG 3.3.2 Labels or Instructions
Proof of Access provides technical accessibility assessments. We are not a law firm and nothing on this page is legal advice. If you have received a demand letter or a lawsuit, talk to an attorney.