Pillar guide
WooCommerce accessibility, end to end
A working map of the whole territory: the two conformance rules that decide whether your checkout counts, the failures that recur in almost every Woo theme, a test pass you can run this afternoon, and an honest account of which of it software can fix and which of it a person has to.
This guide has four jobs: to let you say which parts of the standard actually bite a shop and why checkout is the part that decides it; walk your own store and find the failures that recur in nearly every WooCommerce theme; run a test pass in an afternoon that tells you the truth rather than a comforting number; and put the ten commonest fixes in a defensible order.
Everything below assumes a real store: a theme you bought or inherited, a handful of plugins doing filtering and shipping, and no appetite for a rebuild. That is the normal case, and it is fixable.
What the law actually asks of a shop
Two instruments matter, and they ask for different things.
The European Accessibility Act — Directive (EU) 2019/882, published in the Official Journal on 7 June 2019 — sets accessibility requirements for a list of products and services. Article 2(2) opens: “Without prejudice to Article 32, this Directive applies to the following services provided to consumers after 28 June 2025”, and item (f) on that list is “e-commerce services”. Article 3 defines those as “services provided at a distance, through websites and mobile device-based services by electronic means and at the individual request of a consumer with a view to concluding a consumer contract”. That is a description of a WooCommerce store.
Article 4(5) exempts microenterprises providing services from the service requirements, with a microenterprise defined in Article 3 as “an enterprise which employs fewer than 10 persons and which has an annual turnover not exceeding EUR 2 million or an annual balance sheet total not exceeding EUR 2 million”. A Directive is not directly enforceable prose, though — it is implemented through each Member State’s own law, and the enforcement detail lives there. Whether your shop is in scope, and under which national implementation, is a question for a lawyer. We are not one.
WCAG is the technical yardstick everyone reaches for, because it is the only one specific enough to test. WCAG 2.2 became a W3C Recommendation on 5 October 2023 and was republished as an updated Recommendation on 12 December 2024, and the spec is explicit that “Content that conforms to WCAG 2.2 also conforms to WCAG 2.0 and WCAG 2.1”. Level AA is the working target, and W3C states the requirement precisely: “For Level AA conformance, the web page satisfies all the Level A and Level AA success criteria, or a Level AA conforming alternate version is provided.”
The two conformance rules that decide a shop
Most guidance stops at the criteria. For a store, two of the conformance requirements matter more than any individual criterion.
Full pages. “Conformance (and conformance level) is for full web page(s) only, and cannot be achieved if part of a web page is excluded.” You cannot carve out the third-party review widget or the shipping-calculator plugin because someone else wrote them.
Complete processes. “When a web page is one of a series of web pages presenting a process (i.e., a sequence of steps that need to be completed in order to accomplish an activity), all web pages in the process conform at the specified level or better.” W3C’s own illustration is a shop: “An online store has a series of pages that are used to select and purchase products. All pages in the series from start to finish (checkout) conform in order for any page that is part of the process to conform.”
Read that twice, because it reorders your entire backlog. A beautifully accessible product page attached to a broken payment step buys you nothing — not for the customer, who still cannot finish, and not for a conformance claim, which fails at the weakest step in the chain. The unit of work is the buying journey, not the page.
Where WooCommerce stores actually fail
The failures below are not exotic. They are what a default-ish Woo theme with three or four popular plugins produces, and they cluster in six places.
The product grid
Archive templates repeat one block of markup for every product, so every mistake is multiplied by the page size. The recurring three: product images whose alt text is the uploaded filename or nothing at all (SC 1.1.1 — see image alt text); a column of identical “Read more” or “Add to basket” links whose text tells a screen-reader user nothing about which product they belong to (SC 2.4.4 — see link purpose); and sale, “new” or low-stock state indicated by a coloured badge alone. Colour alone is a Level A failure: “Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element.”
Variations, swatches and the quantity stepper
This is where custom markup does the most damage. Colour and size swatches are frequently div or span elements with a click handler, which means they have no role, no name and no selected state to expose. W3C is direct about the consequence: “If custom controls are created, however, or interface elements are programmed (in code or script) to have a different role and/or function than usual, then additional measures need to be taken to ensure that the controls provide important and appropriate information to assistive technologies and allow themselves to be controlled by assistive technologies.” That is SC 4.1.2.
Three more pile on. Swatches that show selection with a colour change only repeat the 1.4.1 failure. Swatch borders and focus rings need a contrast ratio “of at least 3:1 against adjacent color(s)” under SC 1.4.11 — a criterion no scanner in our set detects, so it is audit territory. And swatches and quantity steppers are usually small: SC 2.5.8 asks that “the size of the target for pointer inputs is at least 24 by 24 CSS pixels”, with exceptions for spacing, inline targets, user-agent-controlled sizing, an equivalent control elsewhere on the page, and essential presentation. A row of eighteen-pixel colour dots packed tight fails on both counts.
The basket
Quantity inputs on a basket table are usually labelled “Quantity” or not labelled at all, so a screen-reader user hears the same name three times with nothing tying it to a product (form labels, SC 1.3.1 and 3.3.2). The remove control is an icon or a bare ”×” with no accessible name (empty links and empty buttons, SC 4.1.2). And when the total updates over AJAX, nothing announces it — which is precisely the case SC 4.1.3 exists for. W3C’s example is a basket: “After a user presses an Add to Shopping Cart button, a section of content near the Shopping Cart icon adds the text ‘5 items’. A screen reader announces ‘Five items’ or ‘Shopping cart, five items’.”
Checkout
The step that costs money when it breaks.
Placeholders standing in for labels is the classic; so is a label that exists visually but is not programmatically associated with its field. Then there is autofill. SC 1.3.5 asks that “the purpose of each input field collecting information about the user can be programmatically determined”, and the technique is the HTML autocomplete attribute, which “only accepts a certain number of specific well-defined fixed values” — given-name, family-name, email, tel, postal-code and the rest. Without those tokens the browser’s stored address is useless and every customer types the whole thing again. See autocomplete.
Error handling is the other half. An error summary that appears above the form but is never announced, and required fields marked with red asterisks and nothing else, are both routine. And SC 3.3.7 Redundant Entry, new in 2.2, asks that information already given “is either: auto-populated, or available for the user to select” — its worked example is “a form on an e-commerce website allows the user to confirm that the billing address and delivery address are the same address”.
Finally: the block checkout and the classic shortcode checkout are different code producing different markup. Test the one you actually ship.
Search, filters and sorting
Faceted filtering is where AJAX and accessibility collide hardest. Applying a filter changes the result count silently, which is a 4.1.3 failure; filter controls built as links carry no pressed or checked state, which is a 4.1.2 failure; and when focus moves into a reloaded results region, a sticky header often covers the focused element. SC 2.4.11 requires that a component receiving focus “is not entirely hidden due to author-created content”, and names the culprits: “Typical types of content that can overlap focused items are sticky footers, sticky headers, and non-modal dialogs.” A cookie or promo bar counts too: “A notification implemented as sticky content, such as a cookie banner, will fail this success criterion if it entirely obscures a component receiving focus.”
The chrome: header, mega menu, footer
Cheap to fix, and it affects every page at once. A missing lang attribute leaves screen readers guessing pronunciation for the whole document (document language, SC 3.1.1). No skip link means tabbing through a mega menu on every page load (skip links, SC 2.4.1). Missing or duplicated landmarks remove the shortcuts screen-reader users navigate by (landmarks). Icon-only search, account and basket buttons in the header have no accessible name. And low-contrast grey on white in prices, meta text and field placeholders fails SC 1.4.3, which asks for a ratio of at least 4.5:1 for normal text and 3:1 for large text (colour contrast). Greyed-out text inside a genuinely inactive control is the one place not to spend the effort: the criterion’s own “Incidental” exception puts text that is part of inactive user interface components outside the contrast requirement.
A test pass that tells you the truth
Four passes, half a day, no licence required. Do them in this order.
1. Automated sweep, on the right pages. Run a scanner over one instance of each template — home, shop archive, a variable product, basket, checkout, search results with filters applied, and your terms page — rather than over the whole catalogue. Nine hundred product pages built from one template produce one finding repeated nine hundred times.
2. Keyboard walk of the buying process. Unplug the mouse. From the home page: reach a category, open a product, choose a variation, set a quantity, add to basket, open the basket, reach checkout, complete every field, and submit. Note every place where focus disappears, where a control cannot be reached or activated, where a drawer traps you, and where the header hides the thing you are on. This single pass finds more real barriers than any tool, because it exercises the process the way the standard defines it.
3. Screen-reader pass on two pages. One variable product, one checkout. Listen for whether swatches announce their name and selected state, whether the quantity field says which product it belongs to, whether “add to basket” confirms anything, and whether checkout errors are read out at all.
4. Zoom and reflow. Zoom in hard and narrow the window. Sticky elements, mega menus, swatch grids and the checkout’s two-column layout are where things overlap, clip or scroll in two directions.
Then be honest about what the tool told you. W3C puts it plainly: “Tools cannot check all accessibility aspects automatically. Human judgement is required” — and “Web accessibility evaluation tools can not determine accessibility, they can only assist in doing so.” When a finding needs judgement about intent, equivalence or brand, that is what the human audit is for.
What automation can and cannot do here
The numbers below come from our own rule tables, not a market average: fifty-five Level A and AA success criteria — thirty-one A, twenty-four AA, spanning WCAG 2.0, 2.1 and 2.2 — in ten fix families, each criterion in exactly one of four honest tiers.
| Tier | What it means for your store | Criteria |
|---|---|---|
| Fixed automatically | Detected and remediated server-side, in the page HTML, deterministically or with a confidence-gated model | 8 |
| Fixed after human approval | Detected and a fix proposed, but a person signs it off — colour contrast is a brand decision | 1 |
| Detected and evidenced | Found, located and reported with the offending markup; the repair is a code change someone makes | 30 |
| Audit only | No reliable automated detection exists; a person has to test it | 16 |
Two numbers in that table carry the whole argument. Thirty-nine of the fifty-five have some automated detection, and not one of them is marked fully automatable in our own data — every one is partial. And the sixteen with no automated detection at all are not obscure edge cases; they include focus order (2.4.3), redundant entry (3.3.7), status messages (4.1.3), non-text contrast (1.4.11), error suggestion (3.3.3), error prevention for financial transactions (3.3.4) and pointer gestures (2.5.1). Those are checkout criteria. Anything claiming to resolve them from a script is claiming something it cannot do.
The split is clean. The mechanical, repetitive, unambiguous failures — a missing lang, nine hundred silent images, a nameless basket button, absent autocomplete tokens — are software’s home ground, fixed server-side in the page HTML with no overlay involved. Judgement is not its ground, and ours does not pretend otherwise: a finding is evidence, and conformance is a human’s word. How it works sets out the mechanism for each family.
Fixing it in a WooCommerce theme
Three rules before any code. Plugin files are off limits — updates overwrite them. A small site plugin outlives a redesign in a way the theme’s functions.php does not. And filters beat template overrides, because a copied template stops receiving upstream fixes the day you copy it.
The autocomplete case is the clearest example of a fix that is pure gain: it satisfies SC 1.3.5 and it shortens the form for every customer using autofill.
<?php
/**
* Give the classic checkout the autocomplete tokens SC 1.3.5 expects.
* Tokens come from the WCAG "Input Purposes for User Interface Components"
* list, which maps onto the HTML autocomplete attribute's fixed values.
*/
add_filter(
'woocommerce_checkout_fields',
function ( array $fields ): array {
$tokens = array(
'billing_first_name' => 'given-name',
'billing_last_name' => 'family-name',
'billing_company' => 'organization',
'billing_address_1' => 'address-line1',
'billing_address_2' => 'address-line2',
'billing_city' => 'address-level2',
'billing_state' => 'address-level1',
'billing_postcode' => 'postal-code',
'billing_country' => 'country',
'billing_email' => 'email',
'billing_phone' => 'tel',
);
foreach ( $tokens as $key => $token ) {
if ( isset( $fields['billing'][ $key ] ) ) {
$fields['billing'][ $key ]['autocomplete'] = $token;
}
}
// Repeat for $fields['shipping'] with the shipping addressing mode.
return $fields;
},
20
);
Check the rendered attributes afterwards rather than trusting the filter: themes and checkout plugins rewrite these arrays, and a later hook can undo you.
The other pattern worth having in muscle memory is the announcement region, because AJAX is everywhere in a shop and SC 4.1.3 is one of the sixteen no scanner will catch for you. Render one region per page, then write to it whenever the basket total, the filter count or a variation’s availability changes.
<!-- Rendered once, early in the template. Uses WordPress's visually-hidden class. -->
<div id="klv-status" role="status" aria-live="polite" class="screen-reader-text"></div>
// After the request that updated the results, not before.
const announce = (message) => {
const region = document.getElementById('klv-status');
if (region) region.textContent = message;
};
jQuery(document.body).on('updated_wc_div', () => {
announce('Basket updated.');
});
Two details do the work here. The region must already be in the DOM when the update happens, so assistive technology is watching it — a region inserted together with its text is usually never announced. And polite lets the message wait for a gap instead of talking over whatever the customer is already listening to. Neither the region nor the message takes focus, which is the shape 4.1.3 asks for: status messages that “can be presented to the user by assistive technologies without receiving focus”.
Keeping it fixed
Conformance is a state, not a property. It drifts on a schedule you already recognise: a product import brings in four hundred images with no alt text; a plugin update rewrites the checkout markup; a seasonal banner arrives in brand colours that miss 4.5:1; a page-builder edit drops a heading level. None of it is a site “going inaccessible” — the site changed, and the standard judges what is served today.
So the operating model is a loop, not a project. Re-scan the same seven templates on a fixed cadence and after every deploy, with the buying process — not just the home page — inside the scanned set. Watch the imports specifically, because catalogue churn is the single largest source of new alt-text failures in a shop. Publish an accessibility statement and keep it current; the WordPress plugin serves one from the same data as the fixes, so it stops being a document someone forgets to update. And treat re-audit as a recurring service rather than a one-off purchase: no scan can certify conformance, and the human audit that does cannot vouch for anything outside its stated scope and date.
The ten fixes, in the order we would do them
Priority here is checkout-first, because the complete-processes rule and the revenue both point the same way, then breadth-first for the failures that affect every page at once.
| # | Fix | Why it is this high | Tier |
|---|---|---|---|
| 1 | Form labels | An unlabelled checkout field is a guess; this is the difference between finishing and abandoning | Automatic |
| 2 | Autocomplete | Restores autofill on the longest form in the store, for the people who need it shortest | Automatic |
| 3 | Empty buttons | Nameless search, basket and quantity buttons cannot be announced or voice-operated | Automatic |
| 4 | Empty links | Icon-only remove, wishlist and quick-view links announce as “link” and nothing else | Automatic |
| 5 | Image alt text | Catalogue-scale, and the failure that regrows with every import | Automatic |
| 6 | Document language | One attribute, whole-site effect, no risk | Automatic |
| 7 | Skip links | Removes a mega menu from every keyboard user’s path on every page | Automatic |
| 8 | Landmarks | Restores the shortcuts screen-reader users navigate by; needs a look before it lands | Human approval |
| 9 | Colour contrast | Real readability gain, but a brand decision — so a person always approves it | Human approval |
| 10 | Link purpose | “Read more” fourteen times; high volume on archives, judgement-heavy per instance | Human approval |
Those ten cover the mechanical failures. The judgement-heavy ones from the audit-only sixteen — focus order through a variation form, whether your error messages actually suggest a correction, whether the payment step lets a customer review and reverse a mistake — are what an audit is for, and they are where the remaining risk sits once the list above is done.
If you want the starting position before you decide any of this, run the free scan at app.klarvoaccess.com against your shop archive and your checkout. It cannot see everything — the sixteen audit-only criteria are the proof — but it will place your store in the right clusters above.
On this subject
The fixes this guide refers to:
- Form fields with no label
- Checkout fields missing an autocomplete purpose
- Buttons with no accessible name
- Links with no discernible text
- Images without alternative text
- Missing document language
- No skip link past repeated content
- Landmark structure problems
- Text that fails colour contrast
- Ambiguous link text
The other guides
- The European Accessibility Act for online shops
- WCAG 2.2 Level AA, for people who run shops
- The checkout, in detail
- Alt text for product images, done properly
- The accessibility statement, written so it survives scrutiny
- Every fix family, with what we do about it
- How the detect → fix → prove → keep loop works
- When a human audit is the honest answer
Sources
- Directive (EU) 2019/882 on the accessibility requirements for products and services (OJ L 151, 7.6.2019, p. 70) (2019-06-07)
- W3C — Web Content Accessibility Guidelines (WCAG) 2.2 (2024-12-12)
- W3C — WCAG 2.2, original Recommendation of 5 October 2023 (2023-10-05)
- W3C WAI — Understanding Conformance (full pages, complete processes) (2026-07-02)
- W3C WAI — Selecting Web Accessibility Evaluation Tools (2026-08-03)
- W3C WAI — Understanding SC 4.1.2 Name, Role, Value (2026-07-02)
- W3C WAI — Understanding SC 4.1.3 Status Messages (2026-07-02)
- W3C WAI — Understanding SC 1.3.5 Identify Input Purpose (2026-07-02)
- W3C WAI — Understanding SC 3.3.7 Redundant Entry (2026-07-02)
- W3C WAI — Understanding SC 1.4.1 Use of Color (2026-07-02)
- W3C WAI — Understanding SC 1.4.3 Contrast (Minimum) (2026-07-02)
- W3C WAI — Understanding SC 1.4.11 Non-text Contrast (2026-07-02)
- W3C WAI — Understanding SC 2.4.11 Focus Not Obscured (Minimum) (2026-07-02)
- W3C WAI — Understanding SC 2.5.8 Target Size (Minimum) (2026-07-02)
Written by the Klarvo Access team. Published 2026-08-04.
FAQ
Questions this raises
Does a WooCommerce accessibility plugin make my store conform?
No plugin can do that on its own, and the honest reason is in the numbers. Of the fifty-five Level A and Level AA success criteria we track — drawn from WCAG 2.0, 2.1 and 2.2 — sixteen have no automated detection at all, focus order, redundant entry, status messages and error suggestion among them, and the remaining thirty-nine are only partially detectable. A server-side plugin can remove a large, real class of failures and give you evidence for the rest. What it cannot do is certify the result: no software issues a conformance certification, because that claim belongs to a qualified human audit, at a stated scope and on a stated date.
Is WCAG 2.1 AA or WCAG 2.2 AA the right target for a shop?
Target 2.1 AA as the floor and treat the 2.2 additions as the near-term backlog. W3C states that content conforming to WCAG 2.2 also conforms to WCAG 2.0 and 2.1, so 2.2 is the safer direction of travel, and several of its new criteria — target size, focus not obscured, redundant entry, accessible authentication — land squarely on shop patterns like swatches, sticky headers and guest checkout.
Do I need to test the block checkout and the classic checkout separately?
Yes. They are different front ends producing different markup, different focus behaviour and different error handling, so a pass on one tells you very little about the other. Test the one your store actually serves, on a real phone as well as a desktop, and retest after any change to the checkout stack.
My store is tiny. Does the European Accessibility Act still apply?
The Directive covers e-commerce services provided to consumers after 28 June 2025, and Article 4(5) exempts microenterprises providing services from the service accessibility requirements — a microenterprise being defined as fewer than ten people with turnover or a balance-sheet total not above two million euros. The Directive is implemented through national law, so whether and how it reaches your shop is a question for your own legal advice, not for us.
Where should I start if I can only fix one thing this week?
Checkout form labels, then autocomplete tokens. Labels are the difference between a form a screen-reader user can complete and one they cannot; autocomplete tokens shorten the form for everyone using autofill, including people for whom typing an address is the hardest part of buying. Both are cheap, both are mechanical, and both sit on the step where abandonment costs you the whole order.
Scan the store this applies to.
Three engines, nine probes, your real pages — home, product, populated basket, hydrated checkout. Free, no signup, and the findings are yours whether or not you buy anything.