skills/storefront-ui/accessibility-commerce/SKILL.md
Make your store usable by everyone with WCAG 2.1 AA compliance — screen reader support, keyboard navigation, and accessible cart and checkout flows
npx skillsauth add finsilabs/awesome-ecommerce-skills accessibility-commerceInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
WCAG 2.1 Level AA compliance covers screen reader announcements for dynamic cart updates, keyboard navigation for interactive components (carousels, quantity steppers, modals), focus management, and color contrast requirements. Accessible stores reduce legal risk under ADA, AODA, and EAA, and typically convert better across all users.
| Platform | Recommended Approach | Why | |----------|---------------------|-----| | Shopify | Use a WCAG-compliant theme (Dawn, Sense) from the Theme Store; install AccessiBe or EqualWeb app for automated overlays; edit Liquid for custom fixes | Shopify's built-in themes have improved a11y significantly; theme editor + Liquid edits handle most issues | | WooCommerce | Choose an accessible theme (Astra, Kadence); install WP Accessibility plugin (free) for skip links, ARIA roles, and form labels | WP Accessibility adds critical fixes without code; Gutenberg blocks have reasonable built-in accessibility | | BigCommerce | Use Cornerstone theme (most accessible); enable the built-in accessibility checker in the Theme Editor; install ADA accessibility apps from the marketplace | Cornerstone meets most WCAG AA requirements out of the box | | Custom / Headless | Implement ARIA patterns manually using the techniques in Step 4; test with NVDA+Firefox and VoiceOver+Safari | Full control requires full responsibility — use the component patterns below |
Before making changes, identify what needs fixing:
Common issues found on most stores:
Theme-level fixes (no code required):
Liquid code fixes for custom themes:
Add ARIA live region for cart updates — edit your cart-notification.liquid or equivalent snippet:
<div aria-live="polite" aria-atomic="true" class="sr-only" id="cart-live-region">
{{ cart.item_count }} items in cart
</div>
For color swatches in variant selectors, wrap in a <fieldset> with <legend>:
<fieldset>
<legend>{{ option.name }}: <span>{{ selected_value }}</span></legend>
{% for value in option.values %}
<label class="swatch {% if forloop.first %}selected{% endif %}">
<input type="radio" name="{{ option.name }}" value="{{ value }}"
{% if value == selected_value %}checked{% endif %} />
<span class="sr-only">{{ value }}</span>
<span class="swatch-color" style="background-color: {{ value | downcase }}" aria-hidden="true"></span>
</label>
{% endfor %}
</fieldset>
App options:
Plugin-based fixes:
Theme-based fixes:
Manual fixes for WooCommerce checkout fields — add to your child theme's functions.php:
// Associate checkout field labels with inputs
add_filter('woocommerce_checkout_fields', function($fields) {
foreach ($fields as $fieldset => &$fieldset_fields) {
foreach ($fieldset_fields as $key => &$field) {
if (!isset($field['label'])) {
$field['label'] = ucfirst(str_replace('_', ' ', $key));
}
}
}
return $fields;
});
Implement these patterns in your React/Vue/Svelte components:
ARIA live region for cart updates:
// Place once at the app root; update message after add-to-cart
export function CartLiveRegion({ message }) {
return (
<div role="status" aria-live="polite" aria-atomic="true"
style={{ position: 'absolute', width: 1, height: 1, overflow: 'hidden', clip: 'rect(0,0,0,0)' }}>
{message}
</div>
);
}
Accessible variant selector using radio inputs:
<fieldset>
<legend>Color: <strong>{selectedColor}</strong></legend>
{colors.map(color => (
<label key={color.value} className={`swatch ${!color.available ? 'unavailable' : ''}`}>
<input type="radio" name="color" value={color.value}
checked={selectedColor === color.value}
disabled={!color.available}
onChange={() => onColorChange(color.value)}
className="sr-only" />
<span className="swatch-visual" style={{ background: color.hex }} aria-hidden="true" />
<span className="sr-only">{color.label}{!color.available ? ' (out of stock)' : ''}</span>
</label>
))}
</fieldset>
Focus management for modals — use native <dialog> which handles focus trapping automatically:
const dialogRef = useRef(null);
useEffect(() => {
if (isOpen) dialogRef.current.showModal();
else dialogRef.current.close();
}, [isOpen]);
return (
<dialog ref={dialogRef} onClose={onClose}>
{/* focus is automatically trapped inside <dialog> */}
<button onClick={onClose} aria-label="Close">×</button>
{children}
</dialog>
);
Visible focus indicators (never remove outlines):
:focus-visible {
outline: 3px solid #2b6cb0;
outline-offset: 2px;
}
:focus:not(:focus-visible) { outline: none; }
Cmd + F5 to enable, navigate using Tab and arrow keys; verify cart updates are announced:focus:not(:focus-visible) so keyboard users retain visible focus<button> for actions, <a> for navigation, <table> for tabular data; ARIA attributes cannot fix non-semantic markup| Problem | Solution |
|---------|----------|
| Cart count badge announced as "3" with no context | Wrap in aria-label="3 items in cart" or use aria-live="polite" region that announces changes with full context |
| Color swatch selection not announced | Use <input type="radio"> with <fieldset>/<legend> wrapping the swatch group; div/span click handlers are invisible to screen readers |
| Modal focus not trapped | Use the native <dialog> element (96%+ browser support) which provides focus trapping for free |
| Form errors not announced | Add role="alert" to error summary or aria-invalid="true" + aria-describedby on each failing field |
| Overlay accessibility apps cause conflicts | Test thoroughly after installing any overlay app — they sometimes break custom theme JavaScript; validate with axe before and after |
tools
Let shoppers save products to a wishlist, share it with friends, and get notified when saved items come back in stock or drop in price
development
Build a themeable storefront with design tokens and CSS custom properties that supports white-labeling, multi-brand variants, and dark mode
development
Speed up product discovery with instant search suggestions, fuzzy typo matching, and category-aware results powered by Algolia or Elasticsearch
development
Build a mobile-first storefront with thumb-friendly navigation, sticky add-to-cart buttons, and touch-optimized components for high mobile conversion