Color Swatches That Say Nothing: Name, Role, Value on Product Options
A row of colored circles looks obvious to a sighted shopper and says nothing to a screen reader. WCAG 2.2 criterion 4.1.2, Name, Role, Value, is the rule, and most stores fail it on swatches.
Pick a color. The product page shows five circles: navy, black, forest, rust, cream. A sighted shopper clicks one and sees the product image change. A screen reader user tabs through the same row and hears button, button, button, button, button. Five buttons, no names, no way to tell which color is which, and no way to know which one is selected.
That is a failure of WCAG 2.2 Success Criterion 4.1.2, Name, Role, Value. Every user interface component needs a name a screen reader can announce, a role it can report, and a value or state it can convey. Swatches fail all three at once, which is why they show up in demand letters so often.
The three failures in one row of circles
First, the name. A swatch button with no text content and no aria-label has no accessible name, so the screen reader announces only its role. The fix is an aria-label on each button with the color name, exactly as the store lists it: Navy, not dark blue, because the shopper needs the name that matches the order confirmation and the return label.
Second, the state. A selected swatch needs aria-pressed="true" on a toggle button, or aria-checked="true" inside a radiogroup. Without it, the shopper cannot tell which color is currently chosen, and she cannot tell whether her click did anything. The visual ring around the selected swatch means nothing to a screen reader.
Third, the role. A group of swatches that behaves like radio buttons should use radiogroup and radio roles, so the screen reader announces that choosing one deselects the others. Plain buttons with pressed states also work, but the group needs a group label, such as Color, so the shopper knows what the five buttons are for before she starts tabbing through them.
Why the image change is not enough
Some teams argue the product image changes when a swatch is picked, so the choice is conveyed. It is not, for two reasons. The image change is visual, and the screen reader does not announce it unless it is wired to a live region. And the image alt text usually describes the product, not the selected color, so even an announced change would not name the color.
The same trap applies to size selectors built from styled divs. A div with an onclick handler has no role at all, so a screen reader announces it as text, or skips it entirely. If the selector looks like a button and acts like a button, mark it up as one, with a real button element or the button role plus keyboard handling.
A checklist for the swatch row
Each swatch is a real button with an aria-label naming the color. The group has a visible label and a group role. The selected swatch reports its state. Arrow keys move between swatches when the group uses radio semantics, and Tab moves into and out of the group as a single stop. The out-of-stock color is disabled, not just greyed out, and its name still announces, with the word unavailable appended.
Test it with the screen off. Tab to the color group, listen to what is announced, pick a color, and confirm you can tell which one is selected without looking. If you cannot, a blind shopper cannot either, and the fix is markup, not a redesign.
Related reading: Touch Targets That Are Too Small: Size, Spacing, and the 24 Pixel Floor, Accessible Authentication: Logins That Do Not Test Memory or Puzzle Solving, Accessible Size and Fit Selectors: Swatches Are Radio Groups, Not Pictures.
Frequently asked questions
Do color swatches need an accessible name?
Yes. WCAG 2.2 criterion 4.1.2 requires every interface component to have a name a screen reader can announce. A swatch button with no text and no aria-label announces as just button, which tells the shopper nothing about which color it is.
How should the selected swatch report its state?
With aria-pressed set to true on a toggle button, or aria-checked set to true inside a radiogroup. The visual ring around the selected swatch means nothing to a screen reader, so the state has to live in the markup.
Should swatches use radio or button semantics?
Either works if it is done consistently. A radiogroup tells the screen reader that picking one deselects the others, and arrow keys move within the group. Plain buttons with pressed states also work, but the group still needs a label such as Color.
What about a swatch that is out of stock?
Disable it properly with the disabled attribute, not just a grey style, and keep its name announcing with the word unavailable appended. A greyed-out swatch that still looks clickable will take a keyboard user into a dead end.