# Size and color selectors AI agents can use: real form controls

> Agent-friendly variant selectors are native radio buttons or select menus with labels, server-rendered inside the add-to-cart form. Choosing a size or color is where AI shopping agents fail most often on product pages, because custom div swatches expose no role or selected state.

- Source: https://is-agentic-storefront.com/checks/variant-controls
- Updated: 2026-10-15
- Category: Operability (20% of score)
- Impact: High
- Spec: [ARIA APG radio group](https://www.w3.org/WAI/ARIA/apg/patterns/radio/)
- Scanner check: Size/color selectors are real form controls

## Why it matters for AI agents

Selecting a variant is the step before add-to-cart, and it is the step where agents most often go wrong. An agent needs to know three things: what the options are (Size: S, M, L), which one is selected, and which combinations are unavailable.

Native form controls expose all three in the accessibility tree that browser agents read. A radio group appears as `radiogroup "Size"` with `radio "M" checked`. A grid of `<div class="swatch">` elements exposes none of it. Screenshot-based agents have their own problem: Anthropic's computer use documentation notes that dropdowns are tricky to operate with a mouse ([computer use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool)), so heavily customized pickers make it worse.

Getting this right also feeds the [add-to-cart form](https://is-agentic-storefront.com/checks/add-to-cart): when variant inputs live inside that form, the selected variant is submitted with the request, with no JavaScript glue needed.

## What the scanner checks

The scanner looks at the server HTML of up to three sampled product pages and finds products with options. It counts:

- **Native controls:** `<select>` elements with more than one `<option>`, or `<input type="radio">`, whose `name` or `id` mentions option, size, color, variant, attribute, swatch, style or material.
- **ARIA controls:** elements with `aria-pressed`, `role="radio"` with `aria-checked`, or `role="option"` with `aria-selected`, inside a form, fieldset or product/variant container.
- **Bare swatches:** `div`, `span`, `li` or `a` elements with swatch-like classes and no `role`.

A product also counts as having variants if its JSON-LD lists more than one variant or SKU. The worst result across products with variants counts.

| Result           | When                                                                                              |
| ---------------- | ------------------------------------------------------------------------------------------------- |
| **Pass**         | Every product with variants uses native selects or radios                                         |
| **Partial**      | At least one product uses ARIA option buttons with state but no native inputs                     |
| **Fail**         | At least one product has bare swatches, or has variants but no option controls in the server HTML |
| **Skipped**      | None of the sampled products have options (excluded from the score)                               |
| **Inconclusive** | No product page could be loaded                                                                   |

## How to fix it

Render each option as a labelled radio group inside the add-to-cart form, with the default selection checked on the server:

```html
<form method="post" action="/cart/add">
  <fieldset>
    <legend>Color</legend>
    <input type="radio" id="color-navy" name="option-color" value="Navy" checked />
    <label for="color-navy">Navy</label>
    <input type="radio" id="color-charcoal" name="option-color" value="Charcoal" disabled />
    <label for="color-charcoal">Charcoal (sold out)</label>
  </fieldset>
  <label for="option-size">Size</label>
  <select id="option-size" name="option-size">
    <option>S</option>
    <option selected>M</option>
    <option>L</option>
  </select>
  <button type="submit">Add to cart</button>
</form>
```

- Style the labels as swatches if you like; keep the inputs in the DOM (visually hidden is fine, `display: none` is not).
- Mark unavailable combinations with `disabled` and say "sold out" in the label text.
- If you must use custom buttons, follow the [ARIA radio group pattern](https://www.w3.org/WAI/ARIA/apg/patterns/radio/): `role="radiogroup"` with a name, children with `role="radio"` and `aria-checked`, and a text name such as "Color: Navy".
- Describe the same variants in structured data with [ProductGroup](https://is-agentic-storefront.com/checks/product-variants) so agents that read JSON-LD get the full matrix.

## Common mistakes

- **Swatches rendered only after hydration**, so the server HTML has variants in JSON-LD but no controls.
- **Color swatches with no text**, only a background color. Add a label or `aria-label` with the color name.
- **Hiding sold-out options entirely**, which makes agents assume the size never existed.

## How to fix it on Medusa

Medusa's [DTC starter](https://github.com/medusajs/dtc-starter) renders option values as plain `<button>` elements with no `aria-pressed` or `aria-checked`, so agents can't tell which option is selected. Either:

- Render each product option as a radio group (`<fieldset>`, `<legend>`, `<input type="radio">` and `<label>`) inside the [add-to-cart form](https://is-agentic-storefront.com/checks/add-to-cart), so the choice is submitted with the server action ([Next.js forms](https://nextjs.org/docs/app/guides/forms)), or
- Keep the buttons and add `role="radio"` with `aria-checked`, inside a container with `role="radiogroup"` named after the option.

Pair it with a `ProductGroup` in the product page's JSON-LD; see the [Medusa agent-readiness guide](https://is-agentic-storefront.com/guides/medusa-agent-readiness).

## Sources

- [ARIA Authoring Practices: radio group pattern](https://www.w3.org/WAI/ARIA/apg/patterns/radio/)
- [WCAG 2.2 SC 4.1.2 Name, Role, Value](https://www.w3.org/TR/WCAG22/#name-role-value)
- [Anthropic: computer use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool)
- [Google: product variants structured data](https://developers.google.com/search/docs/appearance/structured-data/product-variants)

## Frequently asked questions

### Why do AI agents pick the wrong size or color?

When swatches are plain div or span elements, an agent can't tell from the accessibility tree that they are options, which one is selected, or which are sold out. Native radios and selects expose all three.

### Can I style radio buttons as color swatches?

Yes. Keep the native input type=radio with a label and style the label as a swatch. The control stays accessible to agents and screen readers.

### Are ARIA buttons with aria-pressed good enough for variant selection?

They expose state, so agents can use them, and the scanner scores them partial. Native radio groups or selects score a pass because they also submit with the form and need no extra scripting.

## Run your store on a platform built for agentic commerce

Medusa is open-source, headless commerce with a full Store API agents can call and storefronts you control end to end.

### Deploy on Medusa Cloud

Open-source commerce with a full Store API, hosted and scaled for you. Your storefront, your data model.

- [Deploy on Medusa Cloud](https://cloud.medusajs.com?utm_source=agent-friendly-scorer&utm_medium=referral&utm_campaign=markdown-cta&utm_content=%2Fchecks%2Fvariant-controls)
- [Medusa Cloud docs](https://docs.medusajs.com/cloud?utm_source=agent-friendly-scorer&utm_medium=referral&utm_campaign=markdown-cta&utm_content=%2Fchecks%2Fvariant-controls)

### Storefront skills for coding agents

Teach Claude Code, Cursor or Codex to build storefronts with the patterns these checks look for.

```bash
npx skills add medusajs/medusa-agent-skills
```

[View the skill on GitHub](https://github.com/medusajs/medusa-agent-skills/tree/main/plugins/ecommerce-storefront/skills/storefront-best-practices)

---

Scan your store for free at https://is-agentic-storefront.com/