Back to Blog
How to Fix Common Accessibility Issues on Shopify: A Technical Guide — featured image

How to Fix Common Accessibility Issues on Shopify: A Technical Guide

Author avatarVijaygopal Balasa
Updated July 16, 2026
10 min read

This guide explains ten useful accessibility patterns to review on a Shopify storefront, why each matters, and a possible technical remediation. It is not based on a published representative sample and does not imply that every store contains these issues. Confirm the finding, source ownership, and customer impact before changing code.

1. Missing Alternative Text on Images

WCAG Criterion: 1.1.1 Non-text Content | axe-core Rule: image-alt | Severity: Critical

Meaningful images without usable text alternatives can prevent screen-reader users from understanding products or content. Decorative images should instead use an empty alternative, and functional icons need an accessible control name. Inspect both the stored metadata and the published theme output.

Manual fix: In your Liquid template, ensure image tags include the alt attribute:

{% assign img_alt = image.alt | escape | default: product.title | escape %}
<img src="{{ image | img_url: '640x' }}" alt="{{ img_alt }}" width="640" height="640">

AccessComply handling: Eligible missing-alt findings may be reported on reached pages. AI-assisted description or template candidates are limited to supported paths and plan entitlements, require merchant review, and must be verified in the published storefront.

2. Insufficient Color Contrast

WCAG Criterion: 1.4.3 Contrast (Minimum) | axe-core Rule: color-contrast | Severity: Serious

Text that does not meet the 4.5:1 contrast ratio against its background is difficult or impossible to read for users with low vision or color deficiencies. This violation frequently appears in sale badges, footer text, placeholder text, and secondary navigation links.

Manual fix: Adjust the color values in your CSS. For example, change light gray text on a white background from color: #999 to color: #595959 to achieve 4.5:1 against white.

AccessComply handling: A safely source-mapped first-party color candidate may be proposed for merchant approval. Shared variables, imagery, component states, and brand decisions still require manual review and post-change testing.

3. Missing Form Labels

WCAG Criterion: 1.3.1 Info and Relationships | axe-core Rule: label | Severity: Critical

Form inputs without associated labels are announced as "edit text" by screen readers with no indication of what information to enter. This is especially problematic in checkout, account login, and newsletter signup forms.

Manual fix: Wrap each input in a label or use the for attribute:

<label for="email">Email address</label>
<input id="email" type="email" name="customer[email]">

AccessComply handling: Automated rules may report eligible unlabeled controls. Selecting accurate label text and changing first- or third-party markup requires source ownership, safe mapping, merchant approval, and manual form-flow testing.

4. Icon Buttons Without Accessible Names

WCAG Criterion: 4.1.2 Name, Role, Value | axe-core Rule: button-name | Severity: Critical

Cart icons, search icons, and hamburger menus that contain only an SVG icon with no text alternative announce as "button" to screen readers — providing no context. Users with visual impairments cannot tell what the button does.

Manual fix: Add aria-label to icon buttons and aria-hidden to the decorative SVG:

<button type="button" aria-label="Open cart">
  <svg aria-hidden="true" focusable="false">
    <!-- cart SVG path -->
  </svg>
</button>

AccessComply handling: Automated rules may report eligible unnamed controls. The correct accessible name and mechanism require contextual review; third-party app controls usually require vendor coordination.

5. Missing Skip Navigation

WCAG Criterion: 2.4.1 Bypass Blocks | axe-core Rule: bypass | Severity: Serious

Without a skip navigation link, keyboard users must tab through your entire header — logo, navigation links, account icon, cart icon — on every page before reaching the main content. For stores with extensive navigation, this creates a frustrating barrier.

Manual fix: Add a skip link as the first element in layout/theme.liquid:

<a href="#main-content" class="skip-link">Skip to main content</a>

With CSS to show it on focus:

.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px 16px;
  z-index: 9999;
  text-decoration: none;
}
.skip-link:focus {
  top: 0;
}

Add the target ID to your main content section: <main id="main-content" tabindex="-1">.

AccessComply handling: A skip-link candidate may be offered when the relevant first-party template and target are safely source-mapped. A merchant must approve the change and verify it with keyboard and assistive technology.

6. Missing Page Language

WCAG Criterion: 3.1.1 Language of Page | axe-core Rule: html-has-lang | Severity: Serious

Screen readers use the lang attribute on the <html> element to determine which language rules and pronunciation to use. Missing or incorrect language attributes cause screen readers to mispronounce content, which is particularly severe for non-English stores.

Manual fix: In layout/theme.liquid, ensure:

<html lang="{{ request.locale.iso_code }}">

The request.locale.iso_code Liquid variable provides the correct ISO 639-1 language code (e.g., en, fr, de) based on the active store locale.

AccessComply handling: Missing or invalid page-language attributes are automated candidates; the actual locale and multilingual behavior must be verified before a supported source change.

7. Duplicate IDs

WCAG Criterion: 4.1.1 Parsing | axe-core Rule: duplicate-id | Severity: Serious

When the same id attribute value appears multiple times on a page, ARIA attributes that reference those IDs (like aria-labelledby and aria-describedby) break. Screen readers and assistive technologies rely on unique IDs to build accurate accessibility trees.

Repeated sections or custom product grids can generate duplicate IDs when a template does not include a stable unique suffix. Confirm whether any ID reference is ambiguous before editing the source.

Manual fix: In Liquid templates that generate IDs dynamically, include a unique identifier:

<div id="product-{{ product.id }}-{{ forloop.index }}">

AccessComply handling: Automated rules may report eligible duplicate-ID candidates. Changing IDs can break labels, descriptions, scripts, deep links, and app integrations, so remediation needs dependency review and post-change testing.

8. Missing Focus Indicators

WCAG Criterion: 2.4.7 Focus Visible | axe-core Rule: focus-visible | Severity: Serious

Custom theme or app CSS can suppress the browser focus ring with outline: none or outline: 0. If no visible replacement is supplied, keyboard users may not be able to see which element is focused.

Manual fix: Remove outline: none from your CSS or replace it with a visible custom focus style:

/* Remove this: */
*:focus { outline: none; }

/* Add this instead: */
*:focus-visible {
  outline: 2px solid #F97316;
  outline-offset: 2px;
  border-radius: 2px;
}

AccessComply handling: Eligible source-mapped focus-style candidates may be proposed, but contrast, area, clipping, forced-colors behavior, and component-specific states need manual verification.

9. Missing Frame Titles

WCAG Criterion: 4.1.2 Name, Role, Value | axe-core Rule: frame-title | Severity: Serious

Inline frames (<iframe>) without title attributes announce as "frame" to screen readers with no description of their content. Shopify stores commonly embed iframes for reviews (Trustpilot, Judge.me), maps, videos, and chat widgets.

Manual fix: Add an accurate descriptive title to each meaningful iframe you own:

<iframe src="https://widgets.trustpilot.com/..." title="Trustpilot reviews"></iframe>

AccessComply handling: An automated rule may report untitled frames on reached pages. The correct title and ability to change app-owned embeds require manual or vendor review.

10. Table Structure Issues

WCAG Criterion: 1.3.1 Info and Relationships | axe-core Rule: td-headers-attr | Severity: Serious

Data tables without correctly associated headers can be difficult to understand with a screen reader. Size charts, comparison tables, and specification sheets are useful places to inspect, including responsive or app-rendered versions.

Manual fix: Add <th scope="col"> for column headers and <th scope="row"> for row headers:

<table>
  <thead>
    <tr>
      <th scope="col">Size</th>
      <th scope="col">Chest (in)</th>
      <th scope="col">Waist (in)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">S</th>
      <td>34-36</td>
      <td>28-30</td>
    </tr>
  </tbody>
</table>

AccessComply handling: Automated rules may flag structural candidates, but identifying true headers and relationships requires understanding the data. Treat this as manual content review unless the source mapping and semantics are unambiguous.

Automating vs. Manual Fixes

Some first-party findings above may be eligible for a supported, safely source-mapped candidate. Eligibility is not a promise that a change is safe or sufficient. Complex form flows, third-party widgets, documents, captions, and custom interactive components need developer, merchant, specialist, or vendor review.

An AccessComply scan can report eligible automated findings and sample locations on public pages and states it reaches. It cannot determine every issue, route, dynamic state, or manual-only requirement, and a proposed change still needs approval and post-change verification.

Further Reading

Free scan available

Find the storefront issues holding back growth

Scan SEO, speed, and accessibility by page. Review supported fixes before they run, keep saved originals, and verify the live result afterward.

Vijaygopal Balasa, Founder, AccessComply
Written by

Vijaygopal Balasa

Founder, AccessComply

Founder of AccessComply. Builds tools that find and fix supported Shopify accessibility issues in theme code—not through overlays. Focused on practical WCAG 2.2 AA improvements for merchants.

Keep improving after this fix.

Get concise, practical updates on Shopify SEO, speed, accessibility, and safer storefront changes. No daily noise; unsubscribe anytime.

More on Shopify How-To

See all →