Skip to content
Practice & implementation

Accessible Product Pages: Variants, Gallery, Add to Cart

A flaw in the product template appears on every item page. How to make variant choice, gallery, price line and add-to-cart feedback accessible.

15 min read E-CommerceScreenreaderWCAG 2.2

A product detail page is not built anew for every item. It is built once as a template and then filled with data thousands of times. Every item in the range inherits the same variant selection, the same image gallery, the same price line and the same "Add to cart" button. A flaw in that template is therefore not a single finding but a flaw on every product page of the shop. The reverse holds as well: whoever audits and cleans up the template once fixes its flaws across the entire range with one change. This article walks through the components of the product page in order: colour and size selection, unavailable variants, gallery with zoom and full screen, price line with strikethrough and unit price, quantity selector, size chart, delivery time, star rating and the feedback after clicking add to cart. It shows what a screen reader should announce at each point, how the keyboard path through the gallery runs and what an accessible online shop is measured against in an audit.

Key takeaways

  • Home pages in the Shopping category show an average of 71.0 detected errors, 26.6 percent more than the average across all home pages (WebAIM Million, 2026). This survey does not measure product pages.
  • Colour swatches alone are not enough: colour must not be the only visual means of conveying information (W3C, WCAG 2.2, SC 1.4.1). Every variant needs a text name and a state that can be queried (SC 4.1.2).
  • About 9 percent of desktop buttons and 11 percent on mobile have no accessible name (Web Almanac, 2025). Gallery arrows, zoom icons and quantity buttons are typical candidates.
  • Whether a strikethrough price is announced as struck through depends on screen reader, browser and settings. The price line therefore needs audible context such as "now" instead of two bare amounts in a row.
  • After "Add to cart", a status message must confirm the action without moving focus (W3C, WCAG 2.2, SC 4.1.3). A cart icon that silently counts up does not meet this.
  • Violations of the German Accessibility Strengthening Act can be fined up to one hundred thousand euros (BFSG, section 37). The product page is the core of online retail.

Why the template is audited, not every page on its own

An online shop with several thousand items does not usually have thousands of product pages but a single template that is refilled for every item. That changes how an audit is approached. A missing name on the zoom icon, a colour swatch without text or an add-to-cart button without feedback does not appear once but on every single item page. In the audit report it is still only one finding, because the cause sits in one place. That is exactly why it pays to treat the product detail page as a page type: once and thoroughly, with every state a template can take – in stock and sold out, with and without variants, with and without a strikethrough price, with a single image and with a whole image series.

How far retail lags behind is shown by WebAIM's annual survey of the one million most visited home pages. Pages in the Shopping category average 71.0 automatically detected errors, 26.6 percent more than the average of 56.1 errors per page; 95,039 home pages in this category were counted (WebAIM Million, 2026). Overall, 95.9 percent of all home pages tested had detected WCAG failures (WebAIM Million, 2026). Automated tests find only part of the barriers, so these figures are a lower bound, not a complete picture.

What these figures do not measure

The WebAIM survey tests home pages only, not product pages. The Web Almanac evaluates the monthly HTTP Archive crawl of 17 million sites across home and secondary pages (Web Almanac, 2025), but does not report the product detail page as a page type of its own. There is therefore no reliable error rate for the product page itself. The figures describe the state of the sector at its most visible point; what lies beyond the first click only becomes visible when your own templates are audited.

Legally, the product page sits at the core of what the German Accessibility Strengthening Act (BFSG) covers in online retail. Section 1 (3) BFSG expressly lists e-commerce services among the covered services provided to consumers after 28 June 2025 (BFSG). The accompanying ordinance expressly names websites, including the associated online applications (BFSGV, section 12). How the requirements are to be classified in detail is summarised on our page on BFSG requirements. The path to the product page via search and filters is covered in our article on accessible product search, the path afterwards in the article on the accessible checkout.

Variant selection: colour and size as a radio group

The colour swatch is a particularly common finding on product pages because it is so inconspicuous. A round dot of colour shows sighted users which colour is meant – but only as long as they can reliably tell colours apart and recognise the swatch as selectable at all. WCAG requires that colour is not the only visual means of conveying information or distinguishing an element (W3C, WCAG 2.2, SC 1.4.1). For variant selection this means: next to the swatch stands the colour name, visible or at least as text after selection ("Colour: Sage green"). And the selected state is shown not only by a different border colour but also by a check mark or a clearly thicker frame.

Technically, a variant selection is a group of options with exactly one selected. That is exactly what native radio buttons are for: a fieldset with a legend ("Colour"), containing one input type="radio" per variant with a visible or accessible name. Name, role and state of every variant can then be programmatically determined, as SC 4.1.2 requires for all controls (W3C, WCAG 2.2, SC 4.1.2). Whoever builds div elements with click handlers instead has to recreate role, state and keyboard operation and in practice often forgets at least one of them. The keyboard convention for radio groups is defined: Tab moves into and out of the group, the arrow keys change the selection within it (W3C WAI, ARIA Authoring Practices, Radio Group).

SC 1.4.1 Use of Color

Swatches carry a text name, and the selected state is not shown by colour alone (W3C, WCAG 2.2, SC 1.4.1).

SC 4.1.2 Name, Role, Value

Each variant reports name, role and state, for example "Sage green, radio button, checked" (W3C, WCAG 2.2, SC 4.1.2).

SC 1.4.11 Non-text Contrast

Borders and selection marks of the swatches stand out from their surroundings by at least 3:1 (W3C, WCAG 2.2, SC 1.4.11).

SC 2.5.8 Target Size

Colour and size swatches are at least 24 by 24 CSS pixels unless an exception applies (W3C, WCAG 2.2, SC 2.5.8).

SC 2.1.1 Keyboard

All variants can be reached and selected by keyboard, including those that are currently unavailable (W3C, WCAG 2.2, SC 2.1.1).

SC 4.1.3 Status Messages

If price or availability change with the variant, a short status message names the change without moving focus (W3C, WCAG 2.2, SC 4.1.3).

Unavailable variants without a dead end

Sold-out sizes are where well-meant implementations tip over. The common solution of striking through the swatch and locking it with disabled has two consequences: the swatch drops out of the keyboard order, and anyone listening to the page does not learn that the size exists at all. The diagonal line across the swatch is also purely visual information. It is better for the name to carry the state: "Size L, out of stock" – visible next to the swatch and therefore also in the accessible name. The option remains reachable; selecting it shows a note on availability or a notification option instead of the add-to-cart button.

Feedback on dependencies matters too. If someone chooses a colour in which the size already selected is not in stock, the shop must not silently deselect that size. A status message names the change ("Size M not available in Sand, please choose a size"), and the size group shows the new state. Silent state changes are particularly treacherous for screen reader users because they only surface in the cart or in an error message. How such messages are built and worded is described in our article on error and status messages.

On the product page the gallery often carries more information than the description: back view, lining, stitching detail, size comparison on the model. Every view is therefore an image with its own purpose and needs its own alternative text, not the product name five times. WCAG requires a text alternative for all non-text content that serves the equivalent purpose (W3C, WCAG 2.2, SC 1.1.1). WebAIM's home page survey shows how widespread the gap is: 16.2 percent of all images lack alternative text (WebAIM Million, 2026). How good descriptions for product images come about is covered in the article on images and alt text.

The thumbnails below the main image are controls, not decoration. As buttons with names ("View 3 of 5: lining") and a state for the current view, they can be reached by keyboard and told apart by ear. This is where a common finding lies: about 9 percent of desktop buttons and 11 percent on mobile have no accessible name (Web Almanac, 2025). Left and right arrows, the magnifier and the close cross of the full-screen view are the typical candidates because they only show an icon. If the gallery runs as a carousel, the rules from our article on sliders and carousels apply as well.

Zoom and full screen are two different patterns. A magnifier that shows an enlarged section when the mouse hovers over the image can only be operated with a pointer – yet all functionality must also be available through the keyboard (W3C, WCAG 2.2, SC 2.1.1). Content that additionally appears on pointer hover or focus must also be dismissible, hoverable and persistent for as long as it is needed (W3C, WCAG 2.2, SC 1.4.13). Full-screen mode is a dialog: on opening, focus moves into it, Escape closes it, and focus then returns to the element that opened the dialog (W3C WAI, ARIA Authoring Practices, Dialog). What else goes wrong with modal layers is described in the article on modals and overlays.

  • Tab first reaches the full-screen button of the main image, then the thumbnails in reading order
  • Every thumbnail is a button with name and position, and the current view is marked as selected
  • Enter or Space changes the view, and the main image takes over the alternative text of the new view
  • Full screen opens as a dialog, and focus then sits inside the dialog, not on the page behind it
  • Arrow keys page through the full-screen view, Escape closes it, and the page behind cannot be reached meanwhile
  • After closing, focus returns to the button that opened the full-screen view
  • Zoom levels can be reached via plus and minus buttons, not only via mouse wheel or pinch gesture (W3C, WCAG 2.2, SC 2.5.1)

Price line: what the screen reader announces

The price line is the component where visual and audible impression diverge the most. Sighted users take it in at a glance: old price struck through, new price large, below it the unit price and tax note. A screen reader, by contrast, reads the text in source order and, without extra context, often just two amounts in a row: "119.00 euros 99.00 euros". Whether the first amount is recognisable as struck through depends on screen reader, browser and settings – even when the markup uses a del or s element. A template cannot rely on it: in the worst case, anyone listening to the page cannot tell which price applies. The relationship between the amounts that sighted users read from the design must also be present in the text (W3C, WCAG 2.2, SC 1.3.1).

In Germany, the Price Indication Ordinance (PAngV) also makes the price line a mandatory component with fixed content. Anyone announcing a price reduction must state the lowest total price applied within the last 30 days before the reduction (PAngV, section 11). Anyone offering goods by weight, volume, length or area must state the unit price in addition to the total price (PAngV, section 4). These mandatory details only reach all customers once they are also audible in the right context. The solution is unspectacular: every amount gets a word that names its role – visible or as visually hidden text.

Part of the price lineTypical announcementUnambiguous announcement
Strikethrough price"119.00 euros""Lowest price in the last 30 days: 119.00 euros"
Current price"99.00 euros""Now 99.00 euros"
Unit price"4.95 euros slash 1 l""Unit price 4.95 euros per litre"
Tax note"incl. VAT" as an abbreviation"including VAT, plus shipping" with a link
Discount badgeIcon or image without text"Reduced" as text or hidden as decoration
From-price for variants"from 99.00 euros" remains after selectionPrice of the selected variant, change as a status message
product-page.html
<!-- Price line: every amount names its role (SC 1.3.1) -->
<div class="price">
  <p class="price-old">
    Lowest price in the last 30 days:
    <s>€119.00</s>
  </p>
  <p class="price-new">
    <span class="visually-hidden">Now</span>
    <strong>€99.00</strong>
  </p>
  <p class="price-note">incl. VAT, plus shipping</p>
</div>

<!-- Variant selection: native radio buttons with text names (SC 1.4.1, SC 4.1.2) -->
<fieldset class="colours">
  <legend>Colour: <span id="colour-current">Sage green</span></legend>
  <label><input type="radio" name="colour" value="sage" checked>
    <span class="swatch" style="--colour: #7d9a78"></span> Sage green</label>
  <label><input type="radio" name="colour" value="navy">
    <span class="swatch" style="--colour: #22314f"></span> Navy</label>
  <label><input type="radio" name="colour" value="sand">
    <span class="swatch" style="--colour: #d8c7a6"></span> Sand
    <small>out of stock</small></label>
</fieldset>

<!-- Cart: feedback without moving focus (SC 4.1.3) -->
<button type="submit" class="add-to-cart">Add to cart</button>
<p id="cart-status" role="status"></p>

<script>
  // The status region is empty in the DOM on load and only now receives text
  function added(item, count) {
    document.getElementById('cart-status').textContent =
      'Added to cart: ' + item + '. ' + count + ' items in your cart.';
  }
</script>

<style>
  .visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden;
                     clip-path: inset(50%); white-space: nowrap; }
  .colours label { min-inline-size: 24px; min-block-size: 24px; } /* SC 2.5.8 */
  .colours input:focus-visible + .swatch { outline: 3px solid #572899; outline-offset: 2px; }
</style>

Quantity selector, size chart, delivery time and stars

The quantity selector usually consists of a number field and two icon buttons. The field needs a label ("Quantity"), the buttons need names ("Decrease quantity", "Increase quantity") – a minus and a plus sign alone are read as "minus" or not at all. If a click changes the number, the field itself carries the new value so that the screen reader announces it at the next focus. Plus and minus, like all targets, are at least 24 by 24 CSS pixels (W3C, WCAG 2.2, SC 2.5.8); on a phone they otherwise sit close to the edge of the quantity field and are easily missed.

The size chart is a real data table and should be marked up as one: with caption and column and row headers (th with scope), so that a screen reader moving through the cells announces size and measurement together, for example "Size M, chest" followed by the value. Structure and relationships that are visually recognisable must be programmatically determinable (W3C, WCAG 2.2, SC 1.3.1). A size chart as an image does not meet this, nor does a grid of div elements. If the chart opens in its own layer, the same rules apply as for the gallery's full-screen view. Details on header cells and captions are in the article on data tables and complex content.

Delivery time and availability often appear as a coloured dot: green for in stock, yellow for few left, red for sold out. This is exactly the case SC 1.4.1 rules out when the text next to it is missing (W3C, WCAG 2.2, SC 1.4.1). A short sentence such as "In stock, delivery in one to two working days" carries the same information for everyone. Normal text requires a contrast of at least 4.5:1 (W3C, WCAG 2.2, SC 1.4.3) – delivery notes in light green or orange easily miss this value. Low contrast text was found on 83.9 percent of the home pages examined (WebAIM Million, 2026).

The star rating is a graphic with a number inside it. Five star icons, four and a half of them filled, need a text alternative such as "4.5 out of 5 stars" together with the number of reviews – as one continuous text, not as five separate images with the alternative text "star". If the rating is a link to the review section further down, the link text names that destination. Stars as input in a review form, on the other hand, are again a radio group, and the same rules apply as for variant selection.

"Add to cart" with a status message instead of a silent counter

The most important moment on the product page is the click on "Add to cart" – and this is exactly where many shops fall silent. Visually, quite a lot happens: the cart icon in the header counts up, a check mark flashes, sometimes a side panel slides in. Anyone listening to the page notices none of this, because focus stays on the button and nothing changes there. The consequence is predictable: the button is pressed a second and a third time, and the cart holds three jackets instead of one.

For such feedback, WCAG requires that status messages can be programmatically determined through role or properties so that assistive technologies can present them without receiving focus (W3C, WCAG 2.2, SC 4.1.3). In practice this is a region with role="status" that already exists and is empty when the page loads and receives a complete sentence after the item is added: "Added to cart: rain jacket, sage green, size M. 2 items in your cart." How live regions fire reliably and why they must already be in the document on load is explained in the article on ARIA roles, states and live regions.

Mini cart as a dialog

If the shop opens a side panel with the cart contents and buttons such as "Checkout" after adding an item, this is no longer a status message but a dialog. Focus then moves into it, the panel has a heading, Escape closes it, and focus returns to the add-to-cart button. Mixing both – a side panel without focus and without announcement – is the least favourable option: visually intrusive and audibly absent.

The error case also belongs to the template. If "Add to cart" is pressed without a size selected, the error must be described in text and the affected item identified (W3C, WCAG 2.2, SC 3.3.1). In practice: the message "Please choose a size" sits directly at the size group, is linked to it via aria-describedby, and focus moves to the first option of the group. A red border alone is once again a case for SC 1.4.1.

Checklist for the product template

The following table summarises what we check in a product template. It is organised by component, not by success criterion, because development teams think in components and fix findings there. The criteria in the third column come from WCAG 2.2, which for conformance is usually tested at level AA.

ComponentCommon findingWCAG 2.2Test method
Colour swatchescolour area only, no name1.4.1, 4.1.2Screen reader, greyscale view
Size selectionsold-out size hidden via disabled4.1.2, 2.1.1Keyboard, screen reader
Gallerythumbnails without names, duplicated alt text1.1.1, 4.1.2Screen reader
Full screen and zoomfocus stays behind the layer, magnifier mouse-only2.1.1, 2.4.3Keyboard
Price linetwo amounts without a role1.3.1Screen reader in browse mode
Quantity selectorplus and minus without names, targets too small4.1.2, 2.5.8Screen reader, measurement
Size chartimage or grid without table structure1.3.1Table navigation
Delivery timecoloured dot only, light text1.4.1, 1.4.3Contrast measurement
Add-to-cart buttonno status message, counter counts silently4.1.3Screen reader

Keyboard path and screen reader pass through the template

Auditing a product template follows the path of a customer who shops without a mouse. She starts at the top of the page, uses the skip link to reach the main content, reads the heading and price, chooses colour and size, pages through the gallery, opens full screen, closes it again, sets the quantity and adds the item to the cart. At each station we note what is visible, what is announced and where focus sits. The order must preserve meaning and operability (W3C, WCAG 2.2, SC 2.4.3). Visible focus is not a detail: 67 percent of sites explicitly remove the default focus outline (Web Almanac, 2025), and without it keyboard operation gets lost between gallery and variant selection.

How far from self-evident this is in retail is shown by the Aktion Mensch test: only 20 of 65 websites with an online shop that were tested could be operated by keyboard alone (Aktion Mensch, 2025). For the sample of an audit we therefore do not pick arbitrary pages but examples of each page type in every relevant state: with and without variants, in stock and sold out, with strikethrough price, with unit price, with many and with few images. That is exactly how our WCAG audit is structured; the listening pass with several screen readers is described under screen reader testing.

  1. Tab from the skip link to the add-to-cart button: every station reachable, order matching the reading direction
  2. Variant selection with arrow keys: name, state and position are announced, sold-out options with a note
  3. Price line in browse mode: every amount with its role, unit price and lowest price of the last 30 days audible
  4. Gallery: thumbnails with names, full screen opens as a dialog, Escape closes it, focus returns
  5. Trigger the add-to-cart button twice: a status message both times, counter and message match
  6. The same at high magnification and in contrast mode: nothing covered, nothing cut off

From the product page to the shop audit

The product page is not the only template of a shop, but one with particularly high leverage: it is served very often, and it is where the purchase decision is made. Whoever builds it accessibly removes a large share of findings from the whole range before checkout is even reached. The same approach applies to the rest: home page, category page, search, cart, checkout and customer account are each one template that is audited thoroughly once. Which barriers affect older customers in particular is covered in our article on older customers; the buttons for withdrawal and cancellation are covered in the article on the accessible withdrawal button.

For online shops aimed at consumers, the product page usually falls within the scope of the Act; exceptions apply, among others, to micro-enterprises providing services. A violation can be fined up to one hundred thousand euros (BFSG, section 37). In everyday business, however, what is lost at a silent add-to-cart button often weighs more: a purchase that never happens appears in no complaint and in no statistic.

A product page is only finished when you can hear it: every price with its role, every variant with its name, every click with an answer.

Guiding principle for shop templates

The effort for this lies almost entirely in the template. The data – colour names, image descriptions, unit prices, delivery times – is usually already available in the merchandise management system; what is missing is its output in the right place. A change to the template takes effect on every product page after the next rollout, and the audit can be repeated with every new version of the template.

Sources and studies

This article is based on data from the W3C and WAI, WebAIM, the HTTP Archive Web Almanac and Aktion Mensch, and on the wording of the German Accessibility Strengthening Act, its ordinance and the Price Indication Ordinance. The figures cited refer to the status of the respective publication.

Related Articles

Practice & implementation

Accessible Withdrawal and Cancellation Buttons for Shops

Since 19 June 2026, § 356a BGB requires a withdrawal function. How it and the cancellation button work with keyboard, screen reader and zoom.

20 min read
Shop, web & email

Accessible Product Search and Filters in Online Shops

Building search, autocomplete, facet filters and results lists accessibly: the combobox pattern, WCAG 2.2 and a practical test routine for shop teams.

14 min read
German Accessibility Act

Keeping Accessibility: Review Cadence After Go-live

The duty does not end at acceptance. Which events trigger a re-test, which sample size holds up and how long the evidence has to stay on file.

14 min read