Fix the 6 Most Common Accessibility Failures in Your Shopify Theme

Published
Expert reviewed
5 min read
Jacques Blom
Jacques Blom
CTO at Fudge.
Jacques is CTO at Fudge and has been coding since age 13 and building on Shopify for 15+ years. He previously led engineering at several YC-backed startups before joining Fudge to architect its AI Page Builder and Store Editor — systems that have generated 22,000+ production pages for over 400 Shopify merchants. He writes about Shopify performance, theme architecture, and applying LLMs safely to production Liquid code.

Key takeaways

  • Six failures account for the overwhelming majority of accessibility errors on the web, and every one of them turns up on Shopify stores.
  • All six are machine-detectable, so a free scanner finds them in minutes. Each has a specific WCAG success criterion and a specific native-code fix.
  • The fix is always a change to your theme code or an admin field, not a widget layered on top. Overlays leave the underlying failure in place.
  • Automated scanners catch these six because they are unambiguous, but that is only about a third of WCAG, so a manual keyboard and screen-reader pass still matters.

Improving your Shopify accessibility does not start with memorizing all of WCAG. It starts with six specific failures. The annual WebAIM Million study of the top one million home pages finds the same six issues at the top of the list every year, and together they make up the bulk of all detected errors.1

This guide takes each one in turn: what it is, the WCAG success criterion it breaks, how it shows up specifically in a Shopify theme, and the exact fix in native code or the admin. These are the fastest wins because they are common and unambiguous.

Why you can trust us

Jacques has over 15 years of development experience and has helped many Shopify brands ship accessible, fast storefronts. We have been in the Shopify space for over four years and built Fudge, an AI store builder and editor with a 5.0 rating on the Shopify App Store that fixes accessibility issues directly in native theme code. For the legal and standards background behind this work, see our fuller guide to Shopify ADA and WCAG compliance.


The six most common failures at a glance

The February 2026 WebAIM Million report found detectable WCAG failures on 95.9% of home pages, averaging 56.1 errors per page.1 These six categories are where almost all of those errors sit, and the list has barely changed in seven years.

FailureHome pages affectedWCAG success criterionTypical Shopify cause
Low-contrast text83.9%1.4.3 Contrast (Minimum)Brand colors used for body or button text
Missing alt text53.1%1.1.1 Non-text ContentProduct and section images uploaded without alt
Missing form input labels51.0%3.3.2, 4.1.2Search, newsletter, and contact fields
Empty links46.3%2.4.4, 4.1.2Icon-only links (cart, social, logo)
Empty buttons30.6%4.1.2 Name, Role, ValueIcon-only buttons (menu toggle, drawer close)
Missing document language13.5%3.1.1 Language of PageCustom or heavily edited theme.liquid

Percentages are the share of the top one million home pages where WebAIM detected each failure in February 2026.1 Work down the list and you remove most of your risk. For the complete criteria beyond these six, see our WCAG 2.2 AA checklist for Shopify.

1. Low-contrast text

What it is. Text that is too faint against its background to read comfortably. It is the single most common failure on the web, present on the large majority of pages.

Why it fails WCAG. Success criterion 1.4.3 Contrast (Minimum) requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (roughly 18px bold or 24px regular and up). Grey-on-white body copy and pale text on a brand-colored button are the usual offenders.

How it shows up in Shopify. Themes expose color choices as color schemes in the theme editor. A brand palette chosen for its look rather than its contrast flows into body text, buttons, sale badges, and placeholder text across every template at once. A muted grey caption or a light pastel “Add to cart” label can drop well below 4.5:1 without looking obviously broken.

The fix. Adjust the color tokens, not individual elements. In the theme editor, open Theme settings > Colors and raise the contrast of each scheme’s text and button colors until they pass. If you edit code directly, the values live in the theme’s CSS custom properties. In a Dawn-based theme they look like this:

.color-scheme-1 {
  --color-foreground: 18, 18, 18; /* darken text until text-on-background hits 4.5:1 */
  --color-background: 255, 255, 255;
}

Check every pairing with a contrast tool such as the one built into Chrome DevTools or WebAIM’s contrast checker, and remember to test button text against the button fill, not the page background. Fixing the token repairs contrast everywhere the scheme is used.

2. Missing alternative text on images

What it is. An image with no text alternative, so a screen reader announces nothing useful, or reads the file name.

Why it fails WCAG. Success criterion 1.1.1 Non-text Content requires a text alternative for images that convey information. Product photos, informational banners, and content images all need alt text. Purely decorative images need the opposite: an empty alt="" so assistive technology skips them.

How it shows up in Shopify. There are two separate places alt text can go missing:

The fix. Set alt text at the source for each meaningful image, and confirm the theme actually renders it. A theme should output the stored value:

{{ product.featured_image | image_url: width: 800 | image_tag: alt: product.featured_image.alt }}

For a decorative image that adds no information, render an explicit empty alt so screen readers pass over it:

<img src="{{ 'divider.svg' | asset_url }}" alt="" role="presentation" width="1200" height="8">

Write alt text that describes what the image shows and why it is there, and keep it concise.

3. Missing form input labels

What it is. An input a screen reader cannot name, because it has no programmatically associated label. A visible placeholder is not a label. It disappears on focus and many screen readers ignore it.

Why it fails WCAG. Two criteria apply. 3.3.2 Labels or Instructions requires that inputs have labels, and 4.1.2 Name, Role, Value requires that every control expose an accessible name to assistive technology.

How it shows up in Shopify. The recurring culprits are the search field, the newsletter signup, and contact forms. Many themes style these as placeholder-only inputs for a cleaner look:

<input type="email" name="contact[email]" placeholder="Email address">

That renders with no accessible name at all.

The fix. Associate a real <label> with the input by matching for to the input id. If the design calls for no visible label, keep the label in the DOM and hide it with the theme’s visually-hidden utility rather than deleting it:

<label for="NewsletterEmail" class="visually-hidden">Email address</label>
<input
  type="email"
  id="NewsletterEmail"
  name="contact[email]"
  placeholder="Email address"
  autocomplete="email"
>

Dawn and most Online Store 2.0 themes already ship a visually-hidden class, so the label stays available to screen readers while remaining invisible on screen. An aria-label on the input is an acceptable fallback when you cannot add a <label> element.

Find every unlabeled field in your theme code.
Try Fudge for Free

What it is. A link a screen reader announces as “link” with no destination text, because its only content is an icon or image with no text alternative.

Why it fails WCAG. 2.4.4 Link Purpose (In Context) requires that the purpose of a link be clear from its text, and 4.1.2 Name, Role, Value requires an accessible name. An icon-only link satisfies neither.

How it shows up in Shopify. The header and footer are full of these: the cart link rendered as a bag icon, social icons in the footer, the logo link wrapping an SVG, and chevron-only pagination. The markup often looks like this:

<a href="{{ routes.cart_url }}">
  {% render 'icon-cart' %}
</a>

The SVG has no text, so the link has no name.

The fix. Give the link text that a screen reader can read. The cleanest approach is visually-hidden text inside the link, which also lets you include a live count:

<a href="{{ routes.cart_url }}">
  {% render 'icon-cart' %}
  <span class="visually-hidden">Cart, {{ cart.item_count }} items</span>
</a>

An aria-label on the <a> works too. For social icon links, name the network (“Instagram”, “TikTok”) rather than a generic “social link”.

5. Empty buttons

What it is. A <button> with no discernible text, the interactive twin of the empty link. The control works with a mouse but announces nothing to assistive technology.

Why it fails WCAG. 4.1.2 Name, Role, Value requires that every control expose an accessible name. An icon-only button that a screen reader reads as just “button” fails, because the user cannot tell what it does.

How it shows up in Shopify. Icon-only controls are everywhere in modern themes: the mobile menu toggle (hamburger), the cart drawer close button (×), quantity plus and minus controls, and the predictive search open and close buttons. A typical menu toggle:

<button type="button" class="header__icon" aria-expanded="false">
  {% render 'icon-hamburger' %}
</button>

The fix. Add an aria-label describing the action, or place visually-hidden text inside the button:

<button type="button" class="header__icon" aria-expanded="false" aria-label="Open menu">
  {% render 'icon-hamburger' %}
</button>

For a toggle like a menu or cart drawer, pair the label with aria-expanded and keep that attribute in sync with the open state in your theme JavaScript, so screen-reader users know whether the panel is open. A close button should read “Close”, and a quantity control should read “Increase quantity” or “Decrease quantity”.

6. Missing document language

What it is. A page with no lang attribute on its <html> element, so assistive technology does not know which language to read the content in.

Why it fails WCAG. 3.1.1 Language of Page requires that the default human language of each page be programmatically set. Without it, screen readers may use the wrong pronunciation rules for the entire page.

How it shows up in Shopify. This one lives in a single file: theme.liquid, the layout wrapping every page. A well-built theme sets the attribute from the storefront locale. Custom builds and heavily edited themes sometimes hardcode a value, or drop the attribute entirely during a redesign.

The fix. Set lang from the request locale so it stays correct across every market and translated storefront. Open layout/theme.liquid and confirm the opening tag reads:

<!doctype html>
<html
  class="no-js"
  lang="{{ request.locale.iso_code }}"
  dir="{{ request.locale.iso_code | default: 'en' }}"
>

Using {{ request.locale.iso_code }} rather than a fixed "en" means Shopify Markets and multi-language stores serve the right language code to each visitor automatically. This is a one-line change that clears the failure on every page at once.

Why scanners find these six, and what they miss

All six failures share a trait: they are machine-decidable. A tool can prove that an image element has no alt attribute, that a contrast ratio is below 4.5:1, or that a <button> contains no text. That is why a free automated scanner such as axe DevTools, WAVE, or Lighthouse catches them in seconds, and why they dominate the WebAIM Million data. WebAIM measures with automated tooling, so the six most common results are the six most detectable ones.

The catch is that automated detection covers only part of WCAG. Independent testing consistently puts automated coverage at roughly 30 to 40% of the success criteria. The rest needs human judgment: whether alt text is actually meaningful, whether the keyboard focus order makes sense, whether a screen-reader user can complete checkout, whether an error message explains how to fix the problem.

So treat the six as the floor, not the ceiling. After you clear them, do a manual pass:

This is also the reason accessibility overlays do not make a store compliant: a script bolted on at load time cannot supply the judgment the manual layer requires, and it leaves the six underlying failures in the code. If you are still weighing whether the platform covers you, see is Shopify ADA compliant?

Fixing and monitoring the six in native code

Every fix above is a change to your theme code or an admin field. That is deliberate. A real code change is what a developer would ship, what a screen reader actually benefits from, and what holds up if you ever receive a demand letter.

This is where an AI store builder helps. Fudge reads your live theme, surfaces these failures in your Liquid, CSS, and JavaScript, fixes them at the source, and keeps watching for regressions, so a future content edit or app install does not quietly reintroduce one. Because the output is native code rather than an injected layer, there is no extra script slowing the page. It pairs naturally with related work like adding structured data and general store editing.

Clear the six, run one manual pass, and you have removed most of the accessibility risk on a typical store, in the place where it actually lives.


FAQ

What are the six most common accessibility failures on Shopify stores?

Low-contrast text, missing image alt text, missing form input labels, empty links, empty buttons, and a missing document language attribute. The WebAIM Million study finds these same six at the top every year, and all of them are common on Shopify themes and fixable in native code.

Can an automated scanner find all my Shopify accessibility problems?

No. Free tools like axe DevTools, WAVE, and Lighthouse reliably catch the six most common failures because they are machine-decidable, but automated detection covers only about 30 to 40% of WCAG. A manual keyboard and screen-reader pass through checkout is still needed.

How do I add alt text to Shopify product images?

Open the product in the admin, select a media item, and use the Add alt text field in the media detail view. Then confirm your theme renders the stored value, for example with the image_tag filter passing alt: image.alt. Use an empty alt for purely decorative images.

How do I set the language attribute in a Shopify theme?

Edit layout/theme.liquid and set the opening html tag to lang="{{ request.locale.iso_code }}". Using the request locale rather than a hardcoded value keeps the language code correct across Shopify Markets and translated storefronts, and clears WCAG 3.1.1 on every page at once.

Why is a placeholder not enough to label a Shopify form field?

A placeholder disappears once the user starts typing and many screen readers do not treat it as a label, so the field fails WCAG 3.3.2 and 4.1.2. Add a real label element linked by for and id, hidden with the theme's visually-hidden class if you do not want it shown.

How do I fix an icon-only cart or menu button for accessibility?

Give it an accessible name. Add an aria-label to the button or link, or place visually-hidden text inside it, such as "Open menu" or "Cart, 3 items". For toggles, keep aria-expanded in sync with the open state so screen-reader users know the panel's status.

Jacques's signature
Ready to fix these six in native theme code?

Footnotes

  1. WebAIM Million, February 2026 report: 95.9% of the top 1,000,000 home pages had detectable WCAG failures, averaging 56.1 errors per page. Most common failures by share of pages: low-contrast text 83.9%, missing alternative text 53.1%, missing form input labels 51.0%, empty links 46.3%, empty buttons 30.6%, missing document language 13.5%, webaim.org/projects/million. 2 3

Related posts