Quality, Performance, Accessibility, and Shipping Intermediate 12 min read
Accessibility Checklist
A comprehensive accessibility checklist for Shopify themes covering WCAG guidelines, keyboard navigation, screen readers, and inclusive design patterns.
Accessible themes work for everyone, including users with visual, motor, auditory, or cognitive disabilities. Accessibility isn’t just ethical; it improves SEO, usability, and legal compliance.
WCAG Guidelines
Web Content Accessibility Guidelines (WCAG) organize requirements into four principles:
| Principle | Meaning |
|---|---|
| Perceivable | Information must be presentable in ways users can perceive |
| Operable | Interface must be operable by all users |
| Understandable | Content and interface must be understandable |
| Robust | Content must work with assistive technologies |
Accessibility Checklist
Semantic HTML
## Semantic Structure
- [ ] Use proper heading hierarchy (h1 → h2 → h3)- [ ] Only one `<h1>` per page- [ ] Use `<nav>` for navigation regions- [ ] Use `<main>` for primary content- [ ] Use `<header>` and `<footer>` appropriately- [ ] Use `<article>` for self-contained content- [ ] Use `<section>` with headings- [ ] Use `<button>` for actions, `<a>` for navigationExample Structure
<header role="banner"> <nav aria-label="Main navigation"> {# Navigation #} </nav></header>
<main id="main-content" role="main"> <h1>{{ page.title }}</h1>
<article> {# Content #} </article></main>
<footer role="contentinfo"> {# Footer #}</footer>Keyboard Navigation
## Keyboard Accessibility
- [ ] All interactive elements are focusable- [ ] Focus order follows visual order- [ ] Focus is visible (not `outline: none`)- [ ] Skip link to main content- [ ] Escape closes modals/drawers- [ ] Tab trapping in modals- [ ] Arrow keys for menu navigation- [ ] Enter/Space activate buttonsSkip Link
{# First element in body #}<a href="#main-content" class="skip-link"> Skip to main content</a>.skip-link { position: absolute; top: -100%; left: 0; padding: 1rem; background: var(--color-background); z-index: 9999;}
.skip-link:focus { top: 0;}Focus Styles
/* Never remove outlines without replacement */:focus { outline: 2px solid var(--color-primary); outline-offset: 2px;}
/* Modern focus-visible */:focus:not(:focus-visible) { outline: none;}
:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px;}Images and Media
## Images and Media
- [ ] All images have `alt` attributes- [ ] Decorative images use `alt=""`- [ ] Informative images have descriptive alt text- [ ] Complex images have extended descriptions- [ ] Videos have captions- [ ] Audio has transcripts- [ ] Autoplay is disabled or easily stoppedAlt Text Examples
{# Decorative image #}{{ image | image_url: width: 400 | image_tag: alt: '' }}
{# Informative image #}{{ product.featured_image | image_url: width: 600 | image_tag: alt: product.featured_image.alt | default: product.title}}
{# Complex image with extended description #}<figure> {{ image | image_url: width: 800 | image_tag: alt: 'Size chart showing measurements', aria-describedby: 'size-chart-description' }} <figcaption id="size-chart-description"> Detailed size chart with measurements in inches... </figcaption></figure>Forms
## Form Accessibility
- [ ] All inputs have associated labels- [ ] Required fields are indicated- [ ] Error messages are clear and specific- [ ] Errors are announced to screen readers- [ ] Form has logical tab order- [ ] Autocomplete attributes are used- [ ] Input types match content (email, tel, etc.)Accessible Form Example
<form> <div class="form-field"> <label for="email"> Email <span class="required" aria-label="required">*</span> </label> <input type="email" id="email" name="email" required autocomplete="email" aria-describedby="email-error" > <span id="email-error" class="form-error" role="alert" hidden> Please enter a valid email address </span> </div>
<button type="submit">Subscribe</button></form>Color and Contrast
## Color and Contrast
- [ ] Text has 4.5:1 contrast ratio (AA)- [ ] Large text has 3:1 contrast ratio- [ ] UI components have 3:1 contrast- [ ] Color is not the only indicator- [ ] Links are distinguishable from text- [ ] Focus indicators have sufficient contrastColor Indicators
{# Bad: color only #}<span style="color: red;">Out of stock</span>
{# Good: color plus text #}<span class="stock-status stock-status--out"> <span class="visually-hidden">Status:</span> Out of Stock</span>ARIA Attributes
## ARIA Usage
- [ ] Use ARIA only when HTML isn't sufficient- [ ] ARIA labels for icon-only buttons- [ ] aria-expanded for collapsible content- [ ] aria-current for navigation- [ ] aria-live for dynamic content- [ ] role attributes where needed- [ ] aria-hidden for decorative elementsARIA Examples
{# Icon button with label #}<button aria-label="Add to cart"> {% render 'icon-cart' %}</button>
{# Expandable navigation #}<button aria-expanded="false" aria-controls="submenu-1"> Shop</button><ul id="submenu-1" hidden> {# Submenu items #}</ul>
{# Current page in navigation #}<a href="/" {% if template == 'index' %}aria-current="page"{% endif %}> Home</a>
{# Live region for cart updates #}<div aria-live="polite" aria-atomic="true" class="visually-hidden"> {{ cart.item_count }} items in cart</div>Modals and Drawers
## Modal Accessibility
- [ ] Focus trapped inside modal- [ ] Escape key closes modal- [ ] Focus returns to trigger on close- [ ] Background content is inert- [ ] Modal has accessible name- [ ] Close button is labeledModal Pattern
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title" hidden> <h2 id="modal-title">Quick View</h2>
<button class="modal__close" aria-label="Close modal" > × </button>
<div class="modal__content"> {# Content #} </div></div>Screen Reader Utilities
/* Visually hidden but accessible */.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;}
/* Show on focus (for skip links) */.visually-hidden-focusable:focus { position: static; width: auto; height: auto; overflow: visible; clip: auto; white-space: normal;}Product Information
## E-commerce Accessibility
- [ ] Price changes are announced- [ ] Sale prices include original price- [ ] Variant selection is keyboard accessible- [ ] Add to cart confirmation is announced- [ ] Product images have alt text- [ ] Stock status is programmatically indicatedAccessible Price Display
<div class="price"> {%- if product.compare_at_price > product.price -%} <span class="visually-hidden">Regular price:</span> <del aria-hidden="true">{{ product.compare_at_price | money }}</del> <span class="visually-hidden">Sale price:</span> <ins>{{ product.price | money }}</ins> {%- else -%} <span class="visually-hidden">Price:</span> {{ product.price | money }} {%- endif -%}</div>Testing Tools
Automated Testing
## Automated Tools
- [ ] axe DevTools (Chrome extension)- [ ] WAVE Web Accessibility Evaluator- [ ] Lighthouse Accessibility audit- [ ] Pa11y CLIManual Testing
## Manual Testing
- [ ] Keyboard-only navigation- [ ] Screen reader testing (VoiceOver, NVDA)- [ ] Zoom to 200% (check layout)- [ ] Windows High Contrast mode- [ ] Reduced motion preferenceScreen Reader Testing
## Screen Reader Tests
- [ ] Navigate by headings- [ ] Navigate by landmarks- [ ] Read product information- [ ] Complete checkout flow- [ ] Use search feature- [ ] Navigate menusCommon Issues
Quick Fixes
| Issue | Fix |
|---|---|
| Missing alt text | Add descriptive alt or alt="" |
| Low contrast | Increase color contrast |
| Missing form labels | Add <label> with for attribute |
| Non-focusable element | Add tabindex="0" or use button |
| Missing skip link | Add skip link to main content |
| Icon-only button | Add aria-label |
Accessibility Statement
Include in your theme:
{# pages/accessibility.liquid #}
<h1>Accessibility Statement</h1>
<p>We are committed to ensuring our website is accessible to all users.</p>
<h2>Standards</h2><p>We aim to conform to WCAG 2.1 Level AA.</p>
<h2>Feedback</h2><p>If you encounter accessibility issues, please contact us at {{ shop.email }}.</p>Practice Exercise
Audit a theme page for accessibility:
- Run axe DevTools
- Test with keyboard only
- Test with a screen reader
- Fix top 5 issues
- Document improvements
Key Takeaways
- Semantic HTML is the foundation
- Keyboard access for all interactions
- Alt text for meaningful images
- Sufficient contrast for readability
- ARIA supplements, doesn’t replace HTML
- Testing with real assistive technology
- Continuous improvement over perfection
What’s Next?
The next lesson covers SEO Basics in Themes for search engine optimization.
Finished this lesson?
Mark it complete to track your progress.
Discussion
Loading comments...