Skip to content

Storefront accessibility

storefront-accessibility

Build product, cart, and checkout pages that meet WCAG 2.2 AA: keyboard use, visible focus, labels and autocomplete, announced errors and cart updates, contrast, and target size. Use when building or reviewing storefront UI, forms, filters, carousels, or checkout for accessibility.

Version 0.3.2  ·  MIT  ·  Source  ·  Rule

Install this skill

Copy the skill and its rule into your project:

npx @sadrmanesh/commerce-agent-skills add storefront-accessibility

The skill goes to .agents/skills/ and the rule to .agents/rules/. See Command line for other directories.

A shopper who cannot reach the buy button with a keyboard, or does not hear that the cart changed, cannot buy. Aim for WCAG 2.2 level AA on every step from search to order confirmation. The success criteria that matter most in a store are listed in the WCAG checklist.

Procedure

  1. Use native elements first: <button> for actions, <a href> for navigation, <select>, <input type="radio">, and <fieldset> with <legend> for option groups. Add ARIA only where no native element fits.
  2. Make every action work with a keyboard in a logical order, with a visible focus indicator that is not hidden behind sticky headers or cookie banners.
  3. Give every form field a visible <label> and the right autocomplete token (given-name, postal-code, email, tel, cc-number).
  4. Announce changes that happen without a page load: "Added to cart", a new cart total, filter result counts. Use a polite live region (role="status" or aria-live="polite").
  5. On a form error, name the field and the fix in text, link the error summary to the fields, set aria-invalid="true", and move focus to the summary or the first invalid field.
  6. Check color contrast: 4.5:1 for normal text, 3:1 for large text and for focus indicators, borders of inputs, and icons that carry meaning.
  7. Make touch and click targets at least 24 by 24 CSS pixels, or space them so the 24 pixel circle around each does not overlap another.
  8. Test with a keyboard only, a screen reader, 200 percent zoom, and an automated checker on the product, cart, and checkout templates.

Product pages

  • Variation pickers are radio groups or selects with a group label ("Size"). A color swatch has a text name, not only a color. Unavailable options say so in text.
  • Price changes after picking a variation are announced.
  • Images have alt text that says what differs between them ("Back view, blue"). Decorative images have alt="".
  • Carousels have pause controls, do not auto-advance faster than a shopper can read, and can be used with a keyboard.

Cart and checkout

  • Quantity steppers are buttons with names ("Increase quantity of Blue mug"), and the input accepts typed values.
  • Do not ask for the same information twice in one flow. Offer "same as shipping" for billing (WCAG 3.3.7 Redundant Entry).
  • Do not require solving a puzzle or remembering a code to sign in or pay, unless an alternative exists (3.3.8 Accessible Authentication). Allow password managers and pasting one-time codes.
  • Session timeouts warn the shopper and let them extend, so a slow shopper does not lose the cart.
  • The order confirmation page has a clear heading and the order number as text.

Gotchas

  • <div onclick> buttons are not focusable and are not announced as buttons.
  • A placeholder is not a label. It disappears when typing starts and often fails contrast.
  • outline: none without a replacement focus style hides where the keyboard is.
  • Opening a mini-cart drawer without moving focus into it, or without returning focus when it closes, strands keyboard users.
  • Infinite scroll without a "load more" button hides the footer and is hard to navigate by keyboard.
  • Disabled "Place order" buttons with no explanation leave shoppers stuck. Keep it enabled and explain errors on submit.

Verification

  • The whole purchase, from search to confirmation, completes with a keyboard only.
  • A screen reader announces the add-to-cart result and the new cart count.
  • Submitting checkout with an empty postal code moves focus to an error that names the field.
  • Text and focus indicators meet the contrast ratios above.
  • The page is usable at 200 percent zoom and 320 CSS pixels wide without horizontal scrolling.

Evaluation

Worked examples and the checks they must satisfy are in evals/tasks.json.

References

WCAG 2.2 checklist for stores

Level A and AA success criteria that storefronts most often fail. Numbers refer to WCAG 2.2.

Criterion Level In a store
1.1.1 Non-text Content A Product image alt, icon buttons with names, swatches with text
1.3.1 Info and Relationships A Headings, lists, tables for size charts, fieldset and legend for options
1.3.5 Identify Input Purpose AA autocomplete on address, email, phone, and payment fields
1.4.3 Contrast (Minimum) AA 4.5:1 text, 3:1 large text, including sale prices and badges
1.4.10 Reflow AA Usable at 320 CSS pixels wide
1.4.11 Non-text Contrast AA 3:1 for input borders, focus rings, and meaningful icons
2.1.1 Keyboard A Filters, swatches, carousels, mini-cart, and payment fields
2.2.1 Timing Adjustable A Cart or checkout timeouts can be extended
2.2.2 Pause, Stop, Hide A Auto-advancing carousels and countdown banners
2.4.3 Focus Order A Drawers and modals trap and return focus
2.4.7 Focus Visible AA A visible focus style everywhere
2.4.11 Focus Not Obscured (Minimum) AA Sticky headers and cookie banners do not cover focus
2.5.8 Target Size (Minimum) AA 24 by 24 CSS pixels, or enough spacing
3.3.1 Error Identification A Errors in text, naming the field
3.3.3 Error Suggestion AA Say how to fix it: "Enter a 5-digit postal code"
3.3.7 Redundant Entry A "Same as shipping" for billing
3.3.8 Accessible Authentication (Minimum) AA No puzzle or memory test to sign in. Allow paste and password managers.
4.1.2 Name, Role, Value A Custom controls expose role and state, such as aria-expanded and aria-pressed
4.1.3 Status Messages AA Cart updates and result counts in a live region

Live region pattern

<div role="status" class="visually-hidden" id="cart-status"></div>
<script>
  function announceCart(message) {
    const region = document.getElementById("cart-status");
    region.textContent = "";
    requestAnimationFrame(() => { region.textContent = message; });
  }
  // announceCart("Blue mug added to cart. Cart has 3 items.");
</script>

The region must exist in the page before the message is written, or some screen readers miss it.

Evaluation

Fixtures from evals/tasks.json. See evaluation fixtures for how the checks work.

add-to-cart-announcement

The add-to-cart button updates a mini-cart badge with JavaScript. Make the result accessible to screen reader and keyboard users.

Must include: <button>, role="status", focus

Must not include: <div onclick

Worked example

Use a real <button> for add to cart so it is focusable and announced as a button. After the request succeeds, write "Blue mug added to cart. Cart has 3 items." into a role="status" live region that already exists in the page. Update the badge text too, with a visually hidden "items in cart" label.

Leave focus on the button after adding. If the mini-cart drawer opens, move focus into it, trap focus while it is open, and return focus to the button when it closes.

checkout-errors

Review a checkout form whose fields use placeholders as labels and show errors only as red borders. List the fixes.

Must include: <label>, autocomplete, aria-invalid, contrast

Must not include: placeholder is enough

Worked example

Give every field a visible <label> and keep the placeholder only for an example value. Add autocomplete tokens such as given-name, address-line1, postal-code, email, and tel.

On submit, show an error summary with links to each invalid field, write each error in text next to the field, set aria-invalid="true", and move focus to the summary. A red border alone fails for color-blind shoppers, so add an icon and text, and check the border and text contrast against the background.