Accessible Shopify variant pickers and colour swatches
The variant picker is where a shopper chooses colour, size or material, so if it fails, they cannot buy. A picker works for keyboard and screen reader users when each option is a group with a name (a fieldset and legend), each choice is a real radio button or an option in a labelled select, swatches have text names, the selected and sold-out states are shown in more than colour, and price or stock changes are announced. Shopify's free Dawn theme follows this pattern, which makes it a useful reference.23
Why variant pickers go wrong
A picker looks simple, but it carries a lot of information: which options exist, which is selected, which combinations are sold out, and what the price is now. Themes and apps often draw all of that with colour and layout alone. The problems we see most often are:
- swatches that are coloured circles with no text name, so a screen reader announces "button" or nothing at all;
- a selected state shown only by a colour change, which fails people who cannot see the difference;5
- custom dropdowns built from
divelements that cannot be reached or opened with a keyboard; - sold-out options shown only with a strike-through or faded colour;
- a price that changes on screen without anything being announced;
- small, tightly packed swatches that are hard to tap.
Each of these maps to a WCAG 2.2 success criterion, covered below.
The pattern that works: a named group of radio buttons
WCAG asks that information and relationships shown visually are also available in code.4 For a variant picker, the relationship is "these choices belong to the option called Colour". The native way to say that is a fieldset whose legend is the option name, containing one radio button per value. Dawn's variant picker does exactly this: each option is rendered as a fieldset with a legend, and each value as an input type="radio" with a label.23
<fieldset>
<legend>Colour: <span>Navy</span></legend>
<input type="radio" id="c-navy" name="Colour" value="Navy" checked>
<label for="c-navy">Navy</label>
<input type="radio" id="c-sand" name="Colour" value="Sand">
<label for="c-sand">Sand <span class="visually-hidden">sold out</span></label>
</fieldset>Native radio buttons bring the right behaviour for free. In the WAI-ARIA Authoring Practices radio group pattern, Tab moves focus into and out of the group, and the arrow keys move between choices.11 Each control also exposes its name, role and state, which is what WCAG 4.1.2 asks for.9 If you style the radios as swatches or pills, hide the default circle visually but keep the input in the page, so keyboard and screen reader behaviour stays intact.
A native select with a visible label is also a sound choice, especially for long lists such as sizes. The trouble starts with custom dropdowns that imitate a select but are not one; if your theme or app uses one, test it with a keyboard first.
Colour swatches: name every colour
WCAG 1.4.1 says colour must not be the only visual way of conveying information.5 A swatch that shows navy blue is fine, but it must also have a text name. Dawn's swatch picker puts the value in visually hidden text inside each label and shows the selected value next to the option name in the legend, so sighted and screen reader users both get it.23
- Give every swatch a text label with the colour name your shoppers would use, such as "Navy", not a code like "C-104".
- Show the selected swatch with more than colour: a thicker outline, an offset ring or a tick.
- Make the outline or ring visible against the page. WCAG 1.4.11 asks for a contrast of at least 3:1 for the visual parts of controls and their states.6
- Print the selected value as text near the picker, as Dawn does in the legend.2
Light swatches such as white, cream or pale grey need extra care, because a white swatch on a white page has no visible edge. A thin border at 3:1 contrast fixes it.6
Sold-out and unavailable combinations
When one combination is sold out, many themes fade the swatch or draw a line through it. Those are visual cues only. Dawn also adds visually hidden text that says the value is sold out or unavailable, so a screen reader user hears it.3 Do the same: put the words in the label, not just in the styling.5
Think about whether to disable sold-out options entirely. A disabled radio cannot be focused, so a keyboard or screen reader user may not learn the option exists at all. Dawn marks unavailable values with a class and the hidden text rather than removing them.3 Keeping them reachable and clearly labelled lets shoppers find out what is out of stock, and opens the door to a back-in-stock sign-up.
Price, stock and image changes must be announced
Picking a variant usually changes the price, the stock message and the main image. A sighted shopper sees that happen; a screen reader user does not, unless you tell them. Shopify's accessibility guidance for themes is explicit: if a theme changes price and availability when a variant is selected, the change must be communicated to screen readers, with aria-live.1 WCAG 4.1.3 covers the same ground: status messages must be announced without moving focus.10
- Use one polite live region near the price, and update its text after the change, for example "Navy, size 10: $48, in stock".
- Announce once per change. Live regions that repeat the whole product block are noisy.
- Do not move keyboard focus to the price or image; leave it on the option the shopper just chose.
Do not jump to another page when an option is chosen
WCAG 3.2.2 says changing the setting of a control must not cause a change of context, such as loading a new page, unless the user has been told beforehand.8 Most Shopify themes update the page in place, which is fine. Watch for set-ups where each colour is a separate product and choosing a swatch loads that product's page. If you do that, make the swatches links (which people expect to navigate) rather than radio buttons, or say near the picker that choosing a colour opens its page.
Make options big enough to tap
WCAG 2.2 added success criterion 2.5.8, Target Size (Minimum), at level AA: pointer targets should be at least 24 by 24 CSS pixels, unless an exception applies, such as enough space around a smaller target.7 Shopify's own accessibility guidance for themes goes further and asks for at least 44 by 44 pixels for primary touch targets, listing product page variants and options, such as colour, size and quantity, among them.1 Small swatches in a tight grid are the usual failure.
A ten-minute test for your own picker
- Open a product with two or more options. Press Tab until focus reaches the picker. Is the focus clearly visible?
- Use the arrow keys to move between values in one option. Does the selection follow, and does the price or stock message update?
- Turn on a screen reader (VoiceOver on a Mac or iPhone, NVDA on Windows). When you reach the picker, do you hear the option name, the value and whether it is selected?
- Move to a sold-out value. Do you hear that it is sold out?
- Change the variant. Is the new price announced?
- Look at the picker in greyscale (most operating systems have a colour filter setting). Can you still tell which swatch is selected?
- On a phone, try tapping each swatch with your thumb without hitting its neighbour.
For a wider keyboard pass, see how to test your website with only a keyboard; for brand colours that fail contrast, see colour contrast explained; and for theme settings and apps, see how to make a Shopify theme accessible. If you need to change theme code, fix accessibility issues without breaking your theme covers working on a copy.
Checking the rest of the store
An automated check finds some of these problems, such as controls with no accessible name or low contrast, but not all; whether a name makes sense, or whether an announcement is helpful, needs a person (see why automated testing finds some problems but not all). Jralo for Shopify, our app, runs a WCAG 2.2 A and AA check of your homepage and up to five linked pages from inside your Shopify admin, and keeps a dated record of every check.12 You can install Jralo from the Shopify App Store; it is free to install. Disclosure: Jralo is our own product, made by Misimi Corp.
Questions people ask
Are colour swatches allowed under WCAG?
Yes, as long as colour is not the only way the information is given. Each swatch needs a text name that assistive technology can read, and the selected swatch needs an indicator other than colour, such as a thicker border or a tick.
Should a variant picker be radio buttons or a dropdown?
Either can be accessible. Radio buttons in a fieldset with a legend show every choice at once and are what Dawn uses for its swatch and button pickers; a native select with a visible label is also fine. Custom dropdowns built from div elements are where most problems appear.
Does changing the variant need to be announced to screen readers?
Shopify's theme guidance says that if the price and availability change when a variant is selected, the change must also be communicated to screen readers, using aria-live. A short status message such as the new price and whether it is in stock is enough.
How big should variant buttons be?
WCAG 2.2 AA asks for pointer targets of at least 24 by 24 CSS pixels, with exceptions such as enough spacing around smaller targets. Shopify's accessibility guidance for themes asks for 44 by 44 pixels for primary touch targets, and it lists product variants and options among them.
Check your site now
Jralo's free check tests your homepage and up to five pages for accessibility (WCAG 2.2 A and AA) and website QA problems, and tells you which countries' accessibility laws are likely relevant to you. No sign-up.
Run the free checkSources
Every number and legal statement in this post links to one of these sources, read on 27 October 2026.
- Shopify.dev: Accessibility best practices for Shopify themes
- Shopify Dawn theme source: snippets/product-variant-picker.liquid
- Shopify Dawn theme source: snippets/product-variant-options.liquid
- W3C: Understanding WCAG 2.2, Success Criterion 1.3.1 Info and Relationships
- W3C: Understanding WCAG 2.2, Success Criterion 1.4.1 Use of Color
- W3C: Understanding WCAG 2.2, Success Criterion 1.4.11 Non-text Contrast
- W3C: Understanding WCAG 2.2, Success Criterion 2.5.8 Target Size (Minimum)
- W3C: Understanding WCAG 2.2, Success Criterion 3.2.2 On Input
- W3C: Understanding WCAG 2.2, Success Criterion 4.1.2 Name, Role, Value
- W3C: Understanding WCAG 2.2, Success Criterion 4.1.3 Status Messages
- W3C WAI-ARIA Authoring Practices Guide: Radio Group pattern
- Shopify App Store: Jralo listing
More questions
- Why does heading structure matter for screen reader users?
- Visible focus: why removing outlines hurts, and what WCAG 2.2 asks
- Accessible navigation and mega menus
- Accessible product image galleries, sliders and carousels
- How to make a Shopify cart drawer accessible
- The European Accessibility Act: a step-by-step plan for small online sellers
- ADA Title III and websites in plain English
- What to put in an accessibility statement
- How to make a WooCommerce store accessible
- How to fix accessibility issues without breaking your theme
- How to make a Shopify theme accessible: settings, apps and what to check
- Captions, transcripts and audio description for product and marketing video
- What a screen reader user hears on your product page, and how to fix it
- Accessible forms and checkout: labels, errors and autocomplete
- How to test your website with only a keyboard in 10 minutes
- Colour contrast explained: what WCAG asks and how to fix brand colours
- Why automated accessibility testing finds some problems but not all
- How do I write alt text that actually helps?
- What did WCAG 2.2 add to WCAG 2.1?
- How can I prove my website is monitored for accessibility?
- Does the European Accessibility Act apply to my online store?
- Do accessibility widgets make a website ADA compliant?
- Got an ADA website demand letter? What to do first
- How do I check if my website is accessible? A 15-minute method
- Website accessibility laws by country (2026)