Accessible Form Labels and Error Messages: Fixing Checkout Issues

Updated ยท 7 min read

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

ProblemWhat a user experiencesWCAG 2.1 criterion
Input has no label, or the label is not connected to itA screen reader says "edit text" with no hint what to type1.3.1 Info and Relationships, 4.1.2 Name, Role, Value
Placeholder used as the only labelThe hint vanishes once typing starts; it is often low contrast3.3.2 Labels or Instructions, 1.3.1
Required status or format not statedUsers learn a field was required only after failing3.3.2 Labels or Instructions
Error shown only in red, or not announcedUsers who cannot see color, or who use a screen reader, never learn what went wrong3.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:

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:

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)

  1. Reload the checkout and put the mouse aside.
  2. Press Tab through every field. Is the order logical, and is focus always visible?
  3. Submit the form empty. Can you find out, without a mouse, which fields failed?
  4. 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

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.

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.