Start building

Tips

Accessible Shopify sections: a practical checklist

Accessibility in a custom section comes down to a handful of habits in the Liquid, HTML and CSS. Here is each one, with code, and a checklist to finish.

The Klorr teamUpdated 9 min read

  • Accessibility
  • WCAG
  • Liquid
  • Shopify sections

Key takeaways

  • Take alt text from the image setting (image.alt) and let merchants control headings, so the page keeps a logical outline.
  • Use real buttons for actions and links for navigation, with a visible focus style on both.
  • Every slider, accordion and tab set must work with a keyboard; <details> and <summary> give you an accordion for free.
  • Aim for at least 4.5:1 contrast on body text and respect prefers-reduced-motion.
  • Announce cart updates with an aria-live region and label every form field.

A theme can pass an accessibility audit and still ship custom sections that do not. Sections are where the interactive pieces live, such as sliders, accordions, tabs and quick-add buttons, and they are written one at a time, often in a hurry. The guidance below follows WCAG 2.2 level AA, the standard most accessibility laws and audits refer to, applied to the specific things a Shopify section does.

Alt text from the image setting

Merchants write alt text when they upload an image in Shopify's admin. Use it rather than hard-coding a description or leaving alt empty. image_tag reads the image's alt text by default; pass it explicitly if you want a fallback.

section.liquid
{{
  section.settings.image
  | image_url: width: 1200
  | image_tag: alt: section.settings.image.alt, loading: 'lazy'
}}
  • Purely decorative images (a background texture, a divider) should have alt="" so screen readers skip them.
  • An image that is the only content of a link needs alt text describing where the link goes.
  • Do not repeat the visible heading in the alt text of an image right next to it.

Keep a sensible heading order

Screen reader users often move through a page by its headings. A section that uses <h1> because it looked right, or jumps from <h2> to <h5>, breaks that outline. A page should normally have one <h1>, usually the product or page title, and sections below it should use <h2> for their main heading and <h3> for card titles inside.

Because a merchant may place the section anywhere, a select setting for the heading level is a good option, with h2 as the default. Style headings with classes so the visual size does not depend on the tag.

section.liquid
{%- assign tag = section.settings.heading_tag | default: 'h2' -%}
<{{ tag }} class="promo__heading">{{ section.settings.heading | escape }}</{{ tag }}>

If it goes somewhere, it is an <a href>. If it does something on the page, such as open a drawer, add to cart or move a slider, it is a <button type="button">. A clickable <div> cannot be reached with the Tab key or activated with Enter or Space unless you rebuild all of that by hand, and screen readers will not announce it as interactive.

  • Icon-only buttons (arrows, close, heart) need an accessible name: aria-label="Next slide" or visually hidden text.
  • Link text should make sense on its own. "Shop the linen collection" is better than "Click here".
  • Links that open a new tab should say so in their text or label.

Visible focus states

Keyboard users need to see where they are. Never remove the outline without replacing it. :focus-visible shows a focus ring for keyboard users without showing it on every mouse click.

styles.css
.promo a:focus-visible,
.promo button:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

Keyboard support for sliders, accordions and tabs

Accordions

The simplest accessible accordion is native HTML. <details> and <summary> are keyboard-operable and announce their open or closed state with no JavaScript.

markup.html
<details class="faq__item">
  <summary class="faq__question">Do you ship internationally?</summary>
  <div class="faq__answer">
    <p>Yes, to most countries. Rates are shown at checkout.</p>
  </div>
</details>

If you build a custom accordion instead, the trigger must be a <button> with aria-expanded set to true or false and aria-controls pointing at the panel's id, and your script must update aria-expanded whenever it opens or closes.

Sliders and carousels

  • Previous and next controls are buttons with clear labels.
  • Slides that are off screen should not be reachable by Tab; links inside them can be skipped with inert or tabindex="-1" while hidden.
  • Autoplay needs a visible pause button, and should stop when a slide receives focus or the pointer hovers it.
  • A region label such as aria-label="Customer reviews" with aria-roledescription="carousel" helps screen reader users understand what they are in.

Tabs

Tabs follow the WAI-ARIA tabs pattern: a role="tablist" containing role="tab" buttons with aria-selected, each controlling a role="tabpanel". The arrow keys move between tabs, and only the active tab is in the Tab order. If that is more than you need, an accordion is usually a simpler and equally good choice.

Colour contrast

WCAG AA asks for a contrast ratio of at least 4.5:1 for normal body text and 3:1 for large text (roughly 24px regular, or about 18.7px bold) and for interface components such as button borders and focus rings. Text over photographs is the usual failure: add a solid or semi-transparent overlay behind it, and give the merchant a setting to adjust its opacity.

Respect reduced motion

Some visitors set their device to reduce motion because animation makes them unwell. Turn off parallax, autoplay and large transitions when that preference is set.

styles.css
@media (prefers-reduced-motion: reduce) {
  .promo *,
  .promo *::before,
  .promo *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

In JavaScript, check window.matchMedia('(prefers-reduced-motion: reduce)').matches before starting an autoplay timer.

Announce cart updates

When a quick-add button adds a product without leaving the page, a sighted visitor sees the cart count change. A screen reader user hears nothing unless you tell them. Put a polite live region in the section and write a short message into it after the request succeeds.

markup.html
<p class="visually-hidden" aria-live="polite" data-cart-status></p>

Set its text to something like "Linen shirt added to cart" or, on failure, the error message. Keep the region in the page from the start; a live region inserted at the same moment as its message is often not announced.

Label every form field

Newsletter sign-ups, quantity inputs and variant selectors all need a label. A placeholder is not a label: it disappears when the visitor types and is often low contrast. Use a <label for>, visually hidden if the design calls for it, and connect error messages with aria-describedby.

Touch target size

WCAG 2.2 AA requires interactive targets of at least 24 by 24 CSS pixels, or enough spacing around smaller ones. Slider dots and close icons are common offenders. Making targets 44 by 44 pixels, a size widely recommended for touch, is easier on everyone, and padding can enlarge the target without changing how the icon looks.

The checklist

CheckHow
Images have alt textimage.alt from the setting; alt="" if decorative
Heading order is logicalOne h1 per page; sections start at h2
Actions are buttons, navigation is links<button type="button"> vs <a href>
Icon buttons have namesaria-label or visually hidden text
Focus is visible:focus-visible outline, never removed
Everything works by keyboardTab, Enter, Space, arrow keys where expected
Accordions expose state<details>, or aria-expanded on a button
Autoplay can be pausedPause button; stops on focus and hover
Contrast meets AA4.5:1 body text, 3:1 large text and UI
Reduced motion respectedprefers-reduced-motion in CSS and JS
Cart updates announcedaria-live="polite" region
Form fields labelled<label for>; errors via aria-describedby
Touch targets are large enoughAt least 24px; 44px is better

Building it in from the start

Accessibility is part of the quality bar every Klorr generation is checked against, alongside lazy media and scoped JavaScript. If you have specific needs, put them in the prompt ("use details and summary for the FAQ", "add a pause button to the autoplay"); how to write better prompts for Shopify sections has more on that. For the performance side of the same section, see how to speed up Shopify custom sections. Automated tools such as Lighthouse catch some problems, but always try the section with only a keyboard, and with a screen reader if you can.

Questions, answered

How do I add alt text to images in a Shopify section?

Add alt text to the image in the Shopify admin, then output it with image.alt, for example image_tag: alt: section.settings.image.alt. Decorative images should have an empty alt so screen readers skip them.

What contrast ratio does WCAG require for text?

WCAG 2.2 level AA requires at least 4.5:1 for normal text and 3:1 for large text. Interface components such as button borders and focus indicators need at least 3:1 against what is next to them.

Is a Shopify slider accessible?

It can be. The controls must be labelled buttons, off-screen slides should not be reachable by Tab, and autoplay needs a pause button and should stop on focus or hover. Respect prefers-reduced-motion as well.

Should I use details and summary for a Shopify FAQ accordion?

Usually, yes. They work with a keyboard and announce their open or closed state without any JavaScript. A custom accordion needs a button with aria-expanded kept in sync by your script.

How do screen readers know when something is added to the Shopify cart?

Only if you tell them. Keep an aria-live="polite" region in the page and write a short message into it when the add-to-cart request succeeds or fails.

Get the whole section written for you

Describe the section you want. Klorr writes the Liquid, the CSS, the schema and every theme-editor setting — code that lives in your theme and stays yours.