Merchants keep asking whether a Shopify store can reach WCAG AA, usually after a scanner report, a demand letter, or a buyer who cannot finish the purchase path on a keyboard. Most storefronts can get close when you fix the HTML you own. Hosted checkout and new customer accounts stay on Shopify's side of the line.
The ten bugs below are the ones that show up again and again on theme audits: empty alt text, weak contrast, missing labels, vanished focus rings, hover-only menus, colour-only swatches, broken skip links, unnamed icon buttons, drawer focus traps, and silent cart or price updates.
Overlay widgets leave that source HTML unchanged. Theme Liquid, product content, and a ruthless app audit are what move a store toward WCAG AA.
Introduction
Shopify accessibility work fails when teams treat it as a plugin install. The community pattern is consistent: someone asks whether WCAG AA is even possible, someone else recommends an overlay after an ADA letter, and a third thread reports checkout or customer-account errors the merchant cannot edit.
This reflects patterns we see regularly across the Shopify merchant and developer community.
The useful split is ownership. You control theme templates, section settings, product media, and most Online Store 2.0 markup. Apps inject popups, reviews, chat, and filters that ignore keyboard and screen-reader contracts. Shopify hosts checkout and the new customer sign-in, and those surfaces can fail contrast or label checks you will never reach in theme.liquid.
This article is a fix path for the ten ecommerce accessibility bugs that actually block Shopify stores, plus a diagnose-before-you-remediate sequence so you stop paying for overlays that scanners still fail. For the conversion cost of inaccessible themes, see Common Theme Mistakes That Kill Conversion Rates. For how Liquid decides what the browser announces, see Liquid Explained for Store Owners.
What merchants are running into
The first question is usually binary in the merchant's head: is Shopify accessible, or is the whole platform a liability. The operational question is narrower. Which failures sit in your theme and catalogue, which sit in apps, and which sit in Shopify-hosted HTML.
Merchants who try to "bring the shop up to WCAG AA" typically hit the same wall. Theme contrast and labels can be fixed in days. Then an audit flags hosted checkout contrast, missing icon roles, or the new customer account page, and there is no Liquid file to edit. Shopify publishes a checkout accessibility conformance report and still lists partial support on contrast and focus. That is a platform ticket, not a theme sprint.
A second cluster arrives as legal panic. Stores install AccessiBe-class widgets after a demand letter, then discover Lighthouse barely moves and screen readers still announce empty buttons. Overlays can offer user preferences. They do not write alt on product media or give a hamburger button an accessible name.
A third cluster is app sprawl. Reviews, chat, upsell popups, and mega-menu apps inject the worst markup on the page: unlabelled close buttons, focus traps, and star ratings announced as "graphic graphic graphic". That pattern sits beside the subscription pile we mapped in The Hidden Cost of Running a Shopify Store When 12 Apps Quietly Eat Your Margins.
Why this happens
Shopify ships no WCAG toggle. Theme Store review covers performance and code quality rather than accessibility certification. Dawn is a better baseline than most premiums, and a brand palette plus two app embeds will still recreate AA failures.
Themes also optimise for the visual editor. outline: none on buttons looks clean in a desktop mock. Colour swatches built as clickable divs look premium in a demo. Sticky headers look modern until they cover the focused link, which is a WCAG 2.2 failure (2.4.11 Focus Not Obscured).
Content defaults make it worse. If a merchant never fills product image alt text, Liquid outputs an empty alt or a filename. Shopify will fall back to the product title in some contexts, which produces twenty identical announcements of "Navy Hoodie" on one product page.
Shopify accessibility ownership map
How to diagnose it
Run this sequence before you buy an app or rewrite the theme.
Start with a keyboard pass from the skip link through header, search, a collection filter, a product with variants, add to cart, the cart drawer, and customer login. Note every control that has no visible focus, every menu that opens only on hover, and every drawer you cannot close with Escape.
Follow that with a screen-reader sample on one homepage, one product, and the cart, listening for unnamed buttons, duplicate headings, and whether variant or price changes are announced. Then run axe DevTools or Lighthouse on those same URLs and treat the score as a defect list rather than a WCAG percentage.
Tag each defect as theme, content, app, or Shopify-hosted. Theme and catalogue issues belong in a merchant sprint, app defects need removal or a vendor ticket, and hosted defects need a Shopify report plus an accessibility statement that documents the gap. Finish by disabling app embeds one at a time on a duplicate theme, because many supposed theme traps disappear when the reviews or chat widget unloads.
If checkout abandonment already looks healthy in analytics while buyers stall, pair this pass with How to Fix Shopify Checkout Abandonment When Your Funnel Looks Healthy. Accessibility failures are one reason a clean funnel still drops people who never appear as a rage-click.
How to fix it
Fix at the source. Each bug below lists the owner, the failure, and the first remediations that hold up in audits.
1. Missing or generic product image alt text
Owner: catalogue first, theme fallback second.
Shopify themes render alt="". Empty media fields become empty attributes, which scanners flag on every product page. Filenames and repeated product titles are only slightly better.
Write alt that describes the visible product: material, colour, viewpoint. Use alt="" only for decorative images. Add a Liquid fallback such as image.alt | default: product.title | escape so a blank field never ships empty. Then fix the catalogue for hero products, because a title fallback still fails when five images share one name.
2. Insufficient colour contrast
Owner: theme settings and brand palette.
Sale prices, compare-at text, footer links, and placeholder search copy are the usual 1.4.3 failures. Brand accents chosen in isolation often fail 4.5:1 on white. Large text can pass at 3:1. Component borders and focus rings need 3:1 against adjacent colours (1.4.11).
Check every pair in the theme editor, not only the primary button. Hero text on product photography fails whenever the image is pale. Do not rely on an overlay to "boost contrast" for users who never open the widget.
3. Missing form labels
Owner: theme forms, then apps.
Newsletter blocks, cart-attribute line-item properties, and review widgets often use placeholder-only fields. Placeholders disappear on input and fail as the accessible name. Associate a visible <label> with each control, or a persistent aria-label when the design hides the label.
Checkout fields on hosted checkout are Shopify's. Cart attributes you add in Liquid are yours. Plus merchants who inject custom properties through scripts create the unlabelled inputs we see most often on cart audits.
4. Hidden or missing focus indicators
Owner: theme CSS.
outline: none without a replacement fails 2.4.7. Custom buttons, drawer triggers, and swatch radios are the usual casualties. Restore a focus ring with at least 3:1 contrast, and test it on both light and dark sections.
Sticky announcement bars and sticky headers must not cover the focused control (2.4.11). If the bar sits position: sticky, give focused links enough offset, or collapse the bar when keyboard focus moves underneath it.
5. Keyboard-inaccessible menus
Owner: theme header, or the mega-menu app you installed.
Hover-only dropdowns lock out keyboard and many touch users. The menu trigger needs a real button, aria-expanded, and open/close on Enter or Space. Arrow keys inside the submenu are a usability win. Escape should close the menu and return focus to the trigger.
If you rebuilt a mega-menu in custom Liquid, you also inherited heading order, duplicate IDs, and skip-link targets. Duplicate header sections in the editor are an architecture smell, the same class of OS 2.0 drift we cover in Online Store 2.0: What Changed and Why It Matters.
6. Inaccessible variant swatches
Owner: theme product form.
Colour-only swatches fail two ways. Screen readers hear "button" with no name, and sold-out state is a grey wash with no text. Use radio inputs or buttons with an accessible name that includes colour and availability. Selected state needs more than a border colour change.
Custom metafield or metaobject swatches make this worse when the theme only knows Shopify's native colour option. If the picker shows a text label and no swatch, the accessibility fix and the merchandising fix are the same job: the theme must read your data model and still output a named, keyboard-operable control.
7. Missing or broken skip navigation
Owner: theme layout.
A skip link should be the first focusable element and must become visible on focus. The target, usually #MainContent or #main-content, must exist, and activating the link must move keyboard focus, not only scroll the page. Put tabindex="-1" on the main landmark so programmatic focus lands there.
Many Shopify themes omit the link, hide it forever, or point at an ID the layout never renders after a section-group refactor.
8. Icon-only buttons without accessible names
Owner: theme header and search, plus apps.
Cart, search, account, and hamburger controls are often SVGs inside a <button> or <a> with no text. Screen readers announce "button". Add a visually hidden label or aria-label, and hide the SVG with aria-hidden="true". The mobile menu button also needs aria-expanded.
App chat bubbles repeat this failure in the corner of every page. If the vendor will not ship a name, the widget does not belong on a storefront you are trying to take to AA.
9. Drawers, modals, and popups that trap or lose focus
Owner: theme cart drawer and quick view, then apps.
When a cart drawer or quick-view modal opens, focus should move inside it. Tab should cycle through the drawer controls, not the page behind. Escape and the close button should return focus to the trigger. Newsletter popups that appear after ten seconds without moving focus strand keyboard users on the page underneath.
Reviews lightboxes and chat windows are the frequent app offenders. Test them on a duplicate theme with embeds off, then on. If the trap only appears with the app, the fix is vendor pressure or removal, not more theme CSS.
10. Dynamic updates that stay silent
Owner: theme JavaScript on product and cart.
Variant changes update price and availability in the DOM while screen readers stay on the old announcement. Add-to-cart success appears as a drawer animation with no live region. Wrap price and availability in an aria-live="polite" region. Announce cart additions with a short status message.
Sold-out variants should stay focusable and include the sold-out state in the accessible name. A disabled add-to-cart button with no text equivalent is a dead end for keyboard buyers, which is also a conversion bug.
| Bug | Owner | First fix | Effort |
|---|---|---|---|
| Empty or generic image alt | Catalogue + theme fallback | Fill media alt; Liquid default | Low |
| Weak colour contrast | Theme settings | Retune sale, footer, and placeholder pairs | Low |
| Placeholder-only form labels | Theme + apps | Visible label on every input | Low to medium |
| Missing focus ring | Theme CSS | Replace outline: none; check sticky headers | Low |
| Hover-only menus | Theme or mega-menu app | Button trigger, aria-expanded, Escape | Medium |
| Unnamed colour swatches | Product form | Named radios or buttons, including sold-out | Medium |
| Broken skip link | Layout | Visible on focus; real main target | Low |
| Icon buttons with no name | Header + apps | aria-label on cart, search, menu | Low |
| Drawer and popup focus traps | Theme + apps | Move focus in, return on close | Medium |
| Silent price and cart updates | Theme JavaScript | Live regions on price, stock, and ATC | Medium |
Low-effort rows are content and CSS. Medium rows are component behaviour. None of them are solved by a storefront overlay.
When to get help
Stay in-house when the list is alt text, contrast tokens, skip links, and icon labels. Those are catalogue and CSS jobs, and they should be on every theme launch checklist.
Bring in engineering when the failures sit in a custom mega-menu, a metafield swatch picker, a cart drawer that fights app scripts, or a stack where three widgets reintroduce traps after every theme update. That is foundation work, the same class of theme architecture we describe in The Anatomy of a High-Performance Shopify Theme.
Do not hire anyone whose only deliverable is an overlay plus a PDF certificate. Ask for a keyboard test recording, an ownership map, and theme diffs. If checkout or new customer accounts fail contrast you cannot edit, document the gap and report it to Shopify. Pretending an overlay covers hosted HTML will not survive a manual audit.
For a structured pass across theme, apps, and checkout extensions, start with a Shopify stack audit or theme development when the markup itself needs a rebuild.
Conclusion
Shopify accessibility is a storefront programme with a hard ownership line. You can fix the ten bugs that block most WCAG AA attempts on pages you render. You cannot make hosted checkout or new customer accounts perfect from theme.liquid, and you should stop paying overlay apps to pretend otherwise.
Start with a keyboard pass, tag every defect by owner, and remediate theme and catalogue first. Remove or replace apps that inject unnamed controls. Document Shopify-hosted exceptions in an accessibility statement, and keep retesting after theme updates and seasonal popups.
If you want that ownership map written against your live theme and app list, book a stack assessment and we will tell you which bugs you can close this sprint and which ones belong in a platform ticket.



