Accessibility
Mast targets WCAG 2.1 AA compliance throughout. This page documents the specific decisions made to achieve accessible interaction across every component.
Compliance overview
WCAG 2.1 AA is the standard required by the Shopify Theme Store review process and by legal accessibility standards in most jurisdictions. Mast is designed to meet all Level A and Level AA success criteria that apply to a Shopify theme.
1.1.1 Non-text content
All images have alt text. Decorative images use empty alt attributes.
1.3.1 Info and relationships
Semantic HTML conveys all structural relationships (headings, lists, tables, nav, main).
1.4.3 Contrast (minimum)
Body text achieves 7:1 contrast ratio. Large text achieves 4.5:1 minimum.
1.4.11 Non-text contrast
Interactive element boundaries (buttons, inputs, checkboxes) meet 3:1 minimum.
1.4.12 Text spacing
No content loss when line height, letter spacing, and word spacing are overridden.
2.1.1 Keyboard
All interactive elements are reachable and operable by keyboard alone.
2.4.1 Bypass blocks
Skip to content link is the first focusable element on every page.
2.4.7 Focus visible
All focusable elements show a visible focus ring. Custom styles use outline, not box-shadow.
3.1.1 Language of page
lang attribute is set on the html element from Shopify shop.locale.
4.1.2 Name, role, value
All interactive components have accessible names vía aria-label, aria-labelledby, or visible text.
Skip to content link
A skip link is the first focusable element on every page. It is visually hidden until focused, at which point it appears as a visible button above the header. Activating it moves keyboard focus directly to the <main> element, allowing users to bypass repeated header navigation.
<a href="#MainContent" class="skip-to-content-link button visually-hidden"> Skip to content </a> <main id="MainContent" tabindex="-1"> <!-- page content --> </main>
The tabindex="-1" attribute on <main> ensures that keyboard focus can be programmatically moved to it by the skip link even though it is not a natively focusable element.
Keyboard navigation
Every interactive element in Mast is reachable and operable by keyboard alone. The following table documents the keyboard interaction for each component.
| Component | Keyboard interactions |
|---|---|
| Navigation links | Tab / Shift+Tab to navigate between links. Enter to activate. Arrow keys navigate within mega menu dropdowns. |
| Cart drawer | Enter or Space on cart icon opens drawer. Escape closes it. Tab moves focus through drawer items. Focus is trapped inside the open drawer. |
| Mobile nav drawer | Enter or Space on hamburger opens drawer. Escape closes it. Tab moves through all nav links. Focus is trapped inside the open drawer. |
| FAQ accordion | Tab to focus each summary element. Enter or Space toggles open/closed. Arrow keys optionally navigate between items. |
| Variant picker | Tab navigates between variant groups. Arrow keys navigate between option values within a group. Enter or Space selects an option. |
| Lookbook hotspots | Tab focuses each hotspot button. Enter opens the quick-add drawer. Escape closes the drawer. |
| Image gallery | Tab focuses the thumbnail strip. Arrow keys navigate between thumbnails. Enter activates. Zoom opens on Enter, closes on Escape. |
| Search | Enter or Space on the search icon opens the search overlay. Typing begins a search. Arrow keys navigate results. Enter activates a result. Escape closes. |
| Quantity input | Tab focuses the quantity input. Arrow keys increment/decrement. The increment/decrement buttons are also focusable. |
Focus management
Drawers and modals require careful focus management. When a drawer opens, keyboard focus must move into the drawer and be trapped there until the drawer is closed. When the drawer closes, focus must return to the element that triggered it.
Focus trapping
Mast uses a custom focusTrap() utility that finds all focusable elements within a container and intercepts Tab and Shift+Tab key events to cycle focus within the bounds. It handles edge cases like disabled elements and elements hidden with display: none.
Focus restoration
Before opening a drawer or modal, Mast stores a reference to document.activeElement. When the drawer closes, focus is restored to that element. This means keyboard users never lose their place in the page.
inert attribute
When a drawer is open, the page behind it receives the inert attribute. This is a native HTML attribute that removes all elements from the accessibility tree and prevents them from receiving focus, without needing to manually iterate every focusable element on the page.
aria-expanded
Toggle buttons (cart icon, mobile menu, FAQ items) use aria-expanded to communicate the current state to screen readers. The value changes between true and false as the controlled region opens and closes.
Screen reader support
Mast is tested with VoiceOver on macOS/iOS and NVDA on Windows. The following ARIA patterns are used throughout.
| Pattern | Attribute | Usage |
|---|---|---|
| Landmark regions | role, aria-label | header, nav, main, footer, aside, and region landmarks are used throughout. Navigation landmarks have descriptive aria-label attributes to distinguish multiple nav elements. |
| Icon buttons | aria-label | Buttons that show only an icon (cart, search, close) have explicit aria-label text. The icon SVG uses aria-hidden="true" to prevent double announcement. |
| Live cart count | aria-live | The cart item count badge uses aria-live="polite" so screen readers announce count changes after add-to-cart without interrupting the current reading flow. |
| Drawer dialogs | role="dialog", aria-modal, aria-labelledby | Cart and mobile nav drawers use role="dialog" with aria-modal="true" and an aria-labelledby attribute pointing to the drawer heading. |
| Loading states | aria-busy, aria-label | The add-to-cart button uses aria-busy="true" while the cart request is in flight. A visually hidden loading message is announced vía aria-live. |
| Error messages | aria-live, role="alert" | Form validation errors and cart errors use role="alert" to immediately announce to screen readers without requiring focus. |
| Image alt text | alt | Product images use the Shopify image alt field. Decorative images (background textures, divider graphics) use alt="". Images with no alt set fall back to the product title. |
| Visually hidden text | .visually-hidden | Supplemental text for screen readers (e.g., "Add Linen Shirt to cart") is added with a CSS visually-hidden utility class, not display: none or visibility: hidden. |
Reduced motion support
Mast fully supports the prefers-reduced-motion: reduce media query. Users who have enabled the “Reduce motion” option in their operating system preferences will see a simplified, motion-free versión of the theme.
The global reduced motion override in Mast sets all animation and transition durations to 0.01ms, effectively disabling them. Individual animations that serve a functional purpose (such as drawer slide-in) have explicit reduced-motion overrides that replace the animation with an instantaneous opacity transition instead.
Scroll reveal animations
Elements appear at final position immediately. No translate or opacity transition.
Drawer slide-in / slide-out
Drawers fade in/out with a 0.01ms duration instead of the 400ms slide.
Announcement bar rotation
Auto-rotation is disabled. Only the first message is shown.
Testimonial carousel
Auto-advance is disabled. Manual navigation still works.
Lookbook hover animations
Hover scale and overlay fade effects are removed.
Product card hover
Image crossfade on hover is disabled.
Color contrast ratios
WCAG AA requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (18pt or 14pt bold) and UI components. The following ratios are measured for the default Mast preset. The Press and Nocturne presets meet equivalent requirements.
| Combination | Ratio | WCAG AA | Context |
|---|---|---|---|
| Ink (#080604) on Paper (#DEDBC8) | 10.8:1 | Pass | Body text on page background |
| Ink (#080604) on Highlight (#F0EEE4) | 12.1:1 | Pass | Body text on card background |
| Accent (#C4893A) on Paper (#DEDBC8) | 3.2:1 | Pass* | Large heading text only |
| Accent (#C4893A) on Ink (#080604) | 4.9:1 | Pass | Accent color on dark background |
| Paper (#DEDBC8) on Ink (#080604) | 10.8:1 | Pass | Light text on dark (Primary button) |
| Ink (#080604)/10 border | N/A | Pass | 3:1 met for interactive boundaries |
* Accent color on Paper meets the large text threshold (3:1) but not the normal text threshold (4.5:1). Mast only uses accent color at display or large heading scale in contexts where this is acceptable. Body text is always Ink on Paper.
Semantic HTML
Mast uses semantic HTML elements throughout to communicate document structure to browsers, screen readers, and search engines.
| Element | Usage in Mast |
|---|---|
<header> | Site-wide header. Contains the logo, navigation, and utility controls. |
<nav> | Main navigation, breadcrumbs, footer link columns, and pagination. Each nav element has an aria-label to distinguish them. |
<main> | Primary content area of each page. Has id="MainContent" for the skip link target. |
<article> | Blog article content and product descriptions where the content is self-contained and independently distributable. |
<section> | Each theme section is wrapped in a <section> with an aria-labelledby pointing to its heading where present. |
<aside> | Collection filter sidebar on desktop. Product recommendations panel. |
<footer> | Site footer containing link columns, newsletter, and colophon. |
<h1>–<h6> | Strict heading hierarchy maintained within each template. Each page has exactly one h1. Section headings are h2. Subsections are h3. |
<ul> / <ol> | Navigation menus, product feature lists, order item lists, and FAQ item lists where order matters. |
<figure> / <figcaption> | Image caption pairs in Lookbook and Image Banner sections. |
<details> / <summary> | FAQ accordion and Collapsible Content use native HTML disclosure widgets for built-in keyboard support. |
<button> | All interactive controls that are not links use <button> elements, never <div> or <span>. |
<a> | Used only for actual navigation. Never repurposed as a click handler without an href. |
<table> | Product specification tables, size guide measurement tables. Always include <thead>, <th scope>, and <caption>. |
How to test accessibility
- —
axe DevTools
Browser extension by Deque. Run it from the DevTools panel on any page to get an automated accessibility audit. Catches about 30–40% of WCAG issues automatically.
- —
Shopify Theme Checker
Available in the theme editor under Analyze. Includes basic accessibility checks as part of its audit report.
- —
Keyboard-only navigation
Unplug the mouse and navigate the entire storefront using only Tab, Shift+Tab, Enter, Space, and Arrow keys. Verify that every interactive element is reachable and shows a visible focus ring.
- —
VoiceOver (macOS / iOS)
Enable VoiceOver with Command+F5 on Mac or vía Accessibility Settings on iPhone. Navigate with VO+Arrow keys and verify that all interactive elements are announced correctly.
- —
NVDA + Firefox (Windows)
Download NVDA (free screen reader for Windows) and test with Firefox. NVDA is widely used by screen reader users and surfaces different issues than VoiceOver.
- —
Color contrast analyzers
Use the Colour Contrast Analyser desktop app or browser devtools to check contrast ratios when customizing colors. Any combination of text and background must be verified.
Merchant responsibility
Mast provides an accessible foundation, but content entered by merchants can introduce accessibility issues. The following are common merchant-caused issues to avoid:
- —Not filling in the alt text field on product and section images. An empty alt attribute is correct for decorative images, but product images need descriptive alt text.
- —Uploading low-contrast graphic text (e.g., light text on a light background) as an image. The theme cannot check the contrast ratio of text embedded in an image.
- —Using heading levels out of order in the rich text editor (e.g., jumping from h2 to h4).
- —Installing third-party apps that inject inaccessible widgets. Review app accessibility is the app developer's responsibility, not the theme's.
- —Setting color tokens to combinations that fail the contrast ratio requirements documented above.