Why e-commerce requires end-to-end accessibility
Retail sites are multi-step journeys: browse → filter/sort → compare → add to cart → checkout. If any link in that chain fails—an unlabeled filter, a keyboard-inoperable size selector, a hidden “Add to Cart,” or a vague payment error—the purchase dies. For blind and low-vision shoppers, these are not inconveniences; they are service denials. Accessibility aligns with business outcomes: fewer abandoned carts, fewer support tickets, and higher conversion.
Category & search pages: discovery without dead ends
Filters that everyone can use
- Use real controls: checkboxes for multi-select facets, radios for single-select, and buttons/links for “Apply/Reset.” Avoid div-as-control anti-patterns.
- Labels and groups: Each facet needs a visible label (
<fieldset><legend>for the group). Include item counts in text, not just badges. - Keyboard flow: Tab should enter the filter region; arrow keys can move within lists; Space/Enter toggles values; Esc closes drawers.
- Announce results: On apply, update focus to the results heading and use a polite live region: “24 products shown, filtered by Size: M; Color: Blue.”
<aside aria-labelledby="filters-title">
<h2 id="filters-title">Filters</h2>
<fieldset>
<legend>Size</legend>
<label><input type="checkbox" name="size" value="m"> Medium (12)</label>
<label><input type="checkbox" name="size" value="l"> Large (8)</label>
</fieldset>
<button type="button" id="apply-filters">Apply filters</button>
</aside>
<h2 id="results">Results</h2>
<div id="status" aria-live="polite"></div>
<script>
document.getElementById('apply-filters').addEventListener('click', () => {
// ...apply...
document.getElementById('results').focus();
const s = document.getElementById('status');
s.textContent = ''; requestAnimationFrame(() => s.textContent = '24 products shown. Filtered: Size Medium.');
});
</script>
Sort, pagination, and infinite scroll
- Sort: expose a labeled
<select>(e.g., “Sort by”). Move focus to the product grid’s heading after change. - Pagination: ensure each page link is a real link with accessible labels (“Page 2 of 10”). Provide “Next”/“Previous” and indicate current page.
- Infinite scroll: offer a “Load more” button that is focusable and announces newly added items via a live region.
Product cards: make decisions scannable and accessible
- Semantic structure: product title as a link; price as text; rating with a text equivalent (“4.5 out of 5, 126 reviews”).
- Images: meaningful alt for primary image (“Women’s denim jacket, black, style 2047”); decorative badges can be
alt="". - Quick actions: “Add to Cart” or “Quick View” must be real buttons. If “Quick View” opens a dialog, manage focus correctly.
- Focus order: logical: image → title → price → actions; never jump into hidden hover-only controls.
PDP (Product Detail Page): variants, media, and add to cart
Variant selection that works for everyone
- Use radios or a select: Show size/color as labeled radios (with
aria-checked) or a<select>. Avoid unlabeled swatches with only color. - Announce availability: “Size XL—Out of stock” should be part of the option’s accessible name, not hidden in color only.
- Price & promo updates: When selection changes, announce “Price updated: $79.00; Color: Blue; Size: M.”
<fieldset>
<legend>Choose size</legend>
<label><input type="radio" name="size" value="m"> Medium</label>
<label><input type="radio" name="size" value="xl" disabled> XL — Out of stock</label>
</fieldset>
Media galleries
- Keyboard: thumbnails tabbable; Enter swaps the main image; left/right arrows move through images in lightbox mode.
- Alt text: describe variant-specific visuals (“Back view, Blue, size M on model”). Avoid repeating the page title as alt.
- Video: captions on; controls reachable; no auto-play.
Add to cart and confirmations
- Real button:
<button type="button" id="add-to-cart">with a clear label. - Status: announce with a polite live region: “Added to cart: Denim Jacket, Blue, M. Cart total: 2 items.”
- Drawer carts: move focus to the drawer’s heading; trap focus inside; return to trigger when closed.
<div id="cart-status" aria-live="polite"></div>
<script>
document.getElementById('add-to-cart').addEventListener('click', () => {
// ...add...
const s = document.getElementById('cart-status');
s.textContent = ''; requestAnimationFrame(() => s.textContent = 'Added to cart: Denim Jacket, Blue, Medium. Cart total: 2 items.');
});
</script>
Cart: edits, alerts, and totals
- Editable quantities: inputs with labels (“Quantity”); announce limits (“Maximum 4”). Provide buttons with accessible names (“Increase quantity”).
- Promo codes: label the input; announce results (“Code SAVE10 applied: −$8.00”). Keep error copy specific.
- Shipping/taxes: provide estimators with labeled fields and clear error handling; announce updated totals.
- Remove items: ensure “Remove” is a button with an accessible name that includes the product title.
Checkout: the highest-risk step
Forms that complete
- Labels: persistent
<label for>; never rely on placeholders. - Autocomplete tokens:
name,given-name,family-name,address-line1,postal-code,cc-number,cc-exp,cc-csc. - Error messaging: field-specific, adjacent, and announced. Move focus to the first error on submit.
- Timing: warn before session timeout; allow extension; preserve entered data on refresh.
<label for="cc-number">Card number</label>
<input id="cc-number" name="cc-number" inputmode="numeric" autocomplete="cc-number"
aria-describedby="cc-hint cc-error">
<div id="cc-hint" class="hint">No spaces or dashes</div>
<div id="cc-error" class="error" role="alert" hidden>Card number must be 16 digits.</div>
Payment widgets and third-party iframes
- Ensure embedded fields expose labels via the provider’s API and are tabbable in a logical order.
- On validation failure, surface specific messages in your DOM via live regions (not just inside the iframe).
Review & place order
- Expose a clear total and item list in readable text (not only images).
- Primary action must be a keyboard-reachable button with a distinct focus style.
- On success, announce order number and summary; provide a printable HTML confirmation in addition to any PDF.
Mobile considerations
- Don’t disable zoom. Users must be able to pinch to zoom; keep tap targets ≥44px.
- Sticky UI: ensure sticky headers/footers don’t cover focused fields or buttons.
- Orientation: avoid locking; content should reflow at 200% zoom without loss.
Quick 12-point e-commerce accessibility audit
- Keyboard-only from category → checkout; focus always visible.
- Filter panel: labeled controls; “Apply”/“Reset” operable; results announced.
- Sort and pagination are accessible with real links/selects.
- Product cards: title link, price text, rating text, visible actions.
- PDP variant radios/selects: availability announced; price updates announced.
- Gallery: thumbnails and lightbox operable via keyboard; alt conveys variant.
- Add to cart announces success; cart drawer manages focus.
- Cart quantities editable with labels; promo code feedback specific.
- Checkout labels persistent; errors specific and focused; autofill works.
- Payment iframe tabbable; specific error messages exposed to the DOM.
- Confirmation page announces order details; accessible receipt option.
- Mobile: zoom allowed; sticky UI doesn’t hide focus/actions.
Common pitfalls that cause purchase failure
- Color-only indicators for size availability or errors.
- Swatches without text labels (screen reader announces “button” with no context).
- Price sliders that require drag only; add text fields for min/max.
- Cart/checkout buttons hidden behind draw-overs with no keyboard path.
- Generic “There was an error” at payment with no field-level guidance.
Evidence to capture when a store blocks access
If an e-commerce flow denies equal access, document it to make the impact clear:
- Recording or screenshots of the step and attempted action (e.g., toggling a swatch that has no label; pressing Tab past “Place Order”).
- Date/time, URL, device/browser, and any assistive tech in use (“NVDA + Firefox,” “VoiceOver on iPhone”).
- Steps taken (“Selected size M; ‘Add to Cart’ remained disabled with no error”).
- Consequence: abandoned purchase, lost promo window, inability to buy a required item.
Why this is also good business
Accessible shops convert more. Clear labels and forgiving validation reduce friction. Announced state changes improve confidence. Keyboard-friendly components speed power users. These improvements lower support costs and drive repeat business—all while reducing legal risk.
How The Brensilber Law Firm helps (briefly)
When inaccessible shopping flows deny equal access, we help translate lived experience into action—emphasizing precise documentation, measurable impact, and remedies that lead to real fixes. If you encountered barriers like those described here, contact us to discuss options, or explore our Resource Hub for more guides.