Checkout is the single most revenue-sensitive page on your entire site. It is also, more often than any other page, the one nobody has ever tested with a keyboard alone or a screen reader turned on. Product pages get the design reviews. Marketing pages get the A/B tests. Checkout gets shipped once, wired into a payment processor, and then everyone is too afraid to touch it again.
That fear is understandable. It is also exactly why the same seven blockers survive in checkout flows year after year, quietly turning away shoppers who use assistive technology at the one moment they were ready to pay you.
None of these seven are exotic. Each one is a specific, nameable failure you can check for in an afternoon.
The Stat: WCAG's 3.3.1 Error Identification and 3.3.3 Error Suggestion require that form errors be clearly identified in text and, where possible, tell the user how to fix them. (Source: W3C WCAG 3.3.1 / 3.3.3)
1. Fields with no programmatic label
A placeholder that reads "Card number" looks like a label. It is not one. Placeholders sit inside the value space of an input, vanish the instant someone starts typing, and are inconsistently announced by screen readers in the first place. A sighted user glances at the field and moves on. A screen reader user, with the placeholder gone or never read aloud, has no idea what the field is for.
The fix is a real <label> element, connected with a matching for and id, or a wrapping label if you prefer:
<!-- Bad -->
<input type="text" placeholder="Card number">
<!-- Good -->
<label for="card-number">Card number</label>
<input type="text" id="card-number" name="card-number" autocomplete="cc-number">
Every field in the checkout flow, including billing address, shipping method radio buttons, and gift message boxes, needs one of these. There is no field small enough to skip.
2. Errors marked by color alone
A red outline around an invalid field communicates nothing to a shopper who is colorblind, has low vision, or has increased their browser zoom to the point where the outline sits off screen. Color is a visual-only signal, and WCAG's success criteria for non-text contrast and error identification exist specifically because color-only cues fail a meaningful share of your customers.
The fix pairs color with a text label and, ideally, an icon:
<!-- Bad: only a red border -->
<input style="border: 2px solid red">
<!-- Good: text and icon carry the meaning, color reinforces it -->
<input aria-invalid="true">
<span class="error-text">! Enter a valid card number</span>
If you strip the CSS from that second example entirely, a shopper should still know exactly what went wrong from the text alone.
3. Error text that exists but is never associated with the field
This is the blocker that trips up teams who think they already solved the problem above. The error message is right there on the screen, styled correctly, sitting directly under the field. But if it is not wired to the input programmatically, a screen reader announces the field, its label, and nothing else. The error text is invisible to the one audience it was written for.
WCAG 3.3.1 and 3.3.3 both speak directly to this: errors must be identified in text, and that text has to reach the user, not just sit nearby on the page. The mechanism is aria-describedby, paired with aria-invalid and a live region so the announcement fires the moment the error appears, following the pattern in WebAIM's form validation guide:
<label for="email">Email address</label>
<input type="email" id="email" aria-invalid="true" aria-describedby="email-error">
<span id="email-error" role="alert">Enter a valid email address</span>
For a fuller walkthrough of how the identification and suggestion criteria work together, the W3C's own guidance on error identification is worth bookmarking for your dev team.
4. Keyboard traps inside card-entry fields
Some payment widgets, especially iframe-based card entry components from third-party processors, format input as you type: inserting spaces every four digits, auto-inserting slashes in expiry dates, or intercepting Tab to move between an embedded set of sub-fields. Done carelessly, these behaviors can trap keyboard focus inside the widget, where Tab and Shift+Tab stop working entirely, or fire unexpectedly and skip fields the user meant to reach.
There is no universal code snippet here because the failure lives inside third-party iframes you often do not control directly. What you can control is testing it. Tab into the card widget, tab through every sub-field in order, tab back out the other side, and confirm focus never gets stuck. If your payment provider's widget fails this test, that is a vendor conversation worth having before launch, not after a customer complaint.
5. Quantity steppers with no accessible name
The plus and minus buttons next to a cart line item are frequently built as bare icon buttons, a + glyph and a - glyph with no text anywhere in the DOM. Visually the intent is obvious. Announced by a screen reader, both buttons are read as "button," indistinguishable from each other and from every other icon button on the page.
<!-- Bad -->
<button><svg><!-- minus icon --></svg></button>
<input type="number" value="1">
<button><svg><!-- plus icon --></svg></button>
<!-- Good -->
<button aria-label="Decrease quantity">-</button>
<label for="qty" class="visually-hidden">Quantity</label>
<input type="number" id="qty" value="1" min="1">
<button aria-label="Increase quantity">+</button>
The aria-label costs nothing visually and turns two ambiguous buttons into two clearly announced ones.
6. Focus that auto-advances between fields
Auto-advancing focus, where typing the fourth digit of a card number automatically jumps focus to the expiry field, feels like a convenience when you are watching a sighted user tab through smoothly. For a screen reader or switch-access user, it is disorienting. The user did not ask to move. Their assistive technology now announces a field they never navigated to, mid-sentence, and any correction they were about to make in the previous field is lost.
The safest fix is to remove auto-advance entirely and let native Tab order and autocomplete attributes do the work:
<!-- Avoid: JS forcibly moves focus after 4 characters -->
<input maxlength="4" onkeyup="if(this.value.length===4) focusNext()">
<!-- Prefer: native tab order, autocomplete hints, no forced focus jump -->
<input maxlength="4" autocomplete="cc-exp-month">
If a design requirement insists on auto-advance, at minimum make it optional and never let it fire while the field still has an error state pending correction.
7. Session timeouts with no warning
Payment sessions time out for good security reasons. But a hard timeout with no warning disproportionately punishes anyone who takes longer to complete a form: a screen reader user moving field by field, someone with a motor disability using switch access, or a customer using voice control software. They lose their cart contents and have to start over, often without ever understanding why.
WCAG's timing adjustable criterion asks for a warning before time expires, with an option to extend. In practice that means a visible countdown, a dialog offering more time, or simply session lengths generous enough that this scenario is rare. None of this requires giving up the security benefit of a timeout, it requires giving the user a chance to respond to one before it fires silently.
Checking your own checkout
Fixing all seven does not require a checkout rebuild. Most of these are template-level or component-level changes: fix the label pattern once in your shared input component, fix the error association once in your form validation logic, and the fix propagates across every step of the flow.
We've written elsewhere about the bigger picture here. If you want the full framing on why this matters for both compliance and revenue, read Ecommerce Accessibility: A Checkout That Complies and Converts. If you want the business case laid out as a cautionary story, The Silent Killer of Conversion: An Inaccessible Checkout makes that argument in full. And if you want to see what this looks like applied to a real platform, start to finish, I Rebuilt a Shopify Store's Checkout With a Screen Reader On walks through exactly that.
This list is meant to be the reference you come back to: seven specific things to check, in order, the next time someone asks whether your checkout is accessible. If you would rather have someone check it for you, our team can walk your actual checkout flow against all seven and flag exactly where it breaks. Start with our ecommerce accessibility solutions.
If you hit one of these seven and are not sure how to fix it in your specific stack, email experts@wcag.world and talk to a person on our team, or head to our ecommerce accessibility solutions page to get started.
