<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Francisco C. Vazquez</title>
    <description>The latest articles on DEV Community by Francisco C. Vazquez (@xfranv8).</description>
    <link>https://dev.to/xfranv8</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4192075%2Fcced7387-519e-4a76-88a3-af28c80e62ea.jpg</url>
      <title>DEV Community: Francisco C. Vazquez</title>
      <link>https://dev.to/xfranv8</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xfranv8"/>
    <language>en</language>
    <item>
      <title>The European Accessibility Act for WooCommerce &amp; Shopify stores: what actually applies and a 30-minute self-audit</title>
      <dc:creator>Francisco C. Vazquez</dc:creator>
      <pubDate>Sun, 18 Oct 2026 12:34:42 +0000</pubDate>
      <link>https://dev.to/xfranv8/the-european-accessibility-act-for-woocommerce-shopify-stores-what-actually-applies-and-a-4a06</link>
      <guid>https://dev.to/xfranv8/the-european-accessibility-act-for-woocommerce-shopify-stores-what-actually-applies-and-a-4a06</guid>
      <description>&lt;p&gt;I recently ran automated accessibility scans on four EU online stores, three on Shopify and one on WooCommerce, checking four pages on each: home, a collection, a product page and the cart. They scored between 56 and 65 out of 100. Every store had at least one "serious" issue, and three of the four had a "critical" one. None of them were badly built. They were well-designed, popular shops on mainstream themes.&lt;/p&gt;

&lt;p&gt;The European Accessibility Act (EAA) has applied to e-commerce since &lt;strong&gt;28 June 2025&lt;/strong&gt;, and most of what I found is fixable in an afternoon. Here is what applies to you, what "accessible" means in practice, and how to check your own store in about 30 minutes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Not legal advice.&lt;/strong&gt; I'm a developer, not a lawyer. This is my reading of the directive and the national guidance. If you're unsure whether you're in scope, check with your national authority or a lawyer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Who is actually in scope
&lt;/h2&gt;

&lt;p&gt;The EAA (Directive (EU) 2019/882) covers "e-commerce services", which in practice means selling to consumers online. A few points matter for store owners:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It has applied since 28 June 2025.&lt;/strong&gt; It isn't a future deadline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microenterprises that provide services are exempt.&lt;/strong&gt; Under the directive, a microenterprise has &lt;strong&gt;fewer than 10 employees AND&lt;/strong&gt; an annual turnover &lt;strong&gt;or&lt;/strong&gt; annual balance sheet total &lt;strong&gt;of â‚¬2 million or less&lt;/strong&gt;. You need both: the small team and one of the two financial figures under the cap. If you have 12 staff, or 6 staff and â‚¬3M in both turnover and balance sheet, you're not exempt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The exemption covers services, not products.&lt;/strong&gt; If you also make covered products, such as e-readers or certain hardware, the product rules are separate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selling into the EU counts.&lt;/strong&gt; If you sell to EU consumers, being based outside the EU doesn't automatically take you out of scope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enforcement is national.&lt;/strong&gt; Each member state passed its own law and appointed its own authorities. In Germany it's the &lt;strong&gt;BFSG&lt;/strong&gt; (BarrierefreiheitsstÃ¤rkungsgesetz), which entered into force on the same date. Penalties and procedures differ from country to country.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What "accessible" means in practice
&lt;/h2&gt;

&lt;p&gt;The directive's requirements are written in general terms ("perceivable, operable, understandable, robust"). In practice, everyone measures websites against &lt;strong&gt;EN 301 549&lt;/strong&gt;, the European ICT accessibility standard, which applies &lt;strong&gt;WCAG 2.1 Level AA&lt;/strong&gt; to web content.&lt;/p&gt;

&lt;p&gt;One nuance: a new version, EN 301 549 v4.1.1, was published in September 2026 and moves to WCAG 2.2. It hasn't yet been cited in the EU Official Journal under the EAA, so for now &lt;strong&gt;WCAG 2.1 AA is the reference that counts&lt;/strong&gt;. WCAG 2.2 is clearly where this is going, though, so it makes sense to aim for it.&lt;/p&gt;

&lt;p&gt;For a store, that boils down to a few things. A keyboard user can find a product, pick a variant, add it to the cart and pay. A screen reader user hears what every button does. Text is readable. Errors are explained.&lt;/p&gt;

&lt;h2&gt;
  
  
  The theme issues I keep finding, with fixes
&lt;/h2&gt;

&lt;p&gt;In my four scans, the same handful of rules came up again and again. Links or buttons with no accessible name showed up in 3 of 4 stores, low colour contrast in 3 of 4, and images missing alt text in 2 of 4. Here are those issues plus the ones that automated tools often miss.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Icon buttons with no name
&lt;/h3&gt;

&lt;p&gt;The cart, search, wishlist, close (Ã—) and carousel arrow buttons usually contain only an SVG. A screen reader just says "button".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Before --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/cart"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;svg&amp;gt;&lt;/span&gt;â€¦&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- After --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/cart"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Cart (2 items)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;focusable=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;â€¦&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A related problem showed up in two of the stores: the visible label says one thing and the &lt;code&gt;aria-label&lt;/code&gt; says another (for example, the visible text is "Shop now" but &lt;code&gt;aria-label="Banner link"&lt;/code&gt;). Voice-control users say what they see, so the accessible name should &lt;strong&gt;start with the visible text&lt;/strong&gt;, or you can just drop the &lt;code&gt;aria-label&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Alt text
&lt;/h3&gt;

&lt;p&gt;Product images need alt text that describes the product, not the filename. Purely decorative images get an empty alt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"tee-navy.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Organic cotton t-shirt, navy, front view"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"divider.svg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Shopify Liquid, fall back to the product title when the merchant left the alt empty:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight liquid"&gt;&lt;code&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;image&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;image_tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;alt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In WooCommerce, fill in the "Alternative Text" field in the media library. Most themes output it automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Contrast
&lt;/h3&gt;

&lt;p&gt;The usual culprits are light grey prices, "sale" badges, placeholder text and white text on photo banners. AA requires &lt;strong&gt;4.5:1&lt;/strong&gt; for normal text and &lt;strong&gt;3:1&lt;/strong&gt; for large text and for UI components like input borders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* #999 on white is about 2.8:1, which fails */&lt;/span&gt;
&lt;span class="nc"&gt;.price--compare&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#6b6b6b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;/* about 5.3:1, which passes */&lt;/span&gt;
&lt;span class="nc"&gt;.hero__text&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;.55&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;/* scrim behind text on images */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Focus traps (and leaks) in drawers and carousels
&lt;/h3&gt;

&lt;p&gt;Cart drawers and mobile menus are the worst offenders. Either focus stays behind the drawer, or the hidden drawer's links can still be tabbed to. One store had focusable links inside &lt;code&gt;aria-hidden="true"&lt;/code&gt; containers, so they were invisible to screen readers but still reachable by keyboard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Open: move focus in, make the page behind inert&lt;/span&gt;
&lt;span class="nx"&gt;drawer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hidden&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;inert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;drawer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button, a, input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Close (also on Escape): restore&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Escape&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;closeDrawer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;closeDrawer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;drawer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hidden&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;inert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;cartToggle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;hidden&lt;/code&gt; or &lt;code&gt;inert&lt;/code&gt; instead of &lt;code&gt;aria-hidden&lt;/code&gt; on content that contains links. For carousels, every slide that's off screen should be &lt;code&gt;inert&lt;/code&gt;. Scrollable rows also need to be reachable by keyboard, either with &lt;code&gt;tabindex="0"&lt;/code&gt; and a label, or with focusable items inside.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Viewport zoom lock
&lt;/h3&gt;

&lt;p&gt;One store still had this in its theme, on every page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Before: blocks pinch-zoom --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- After --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Cookie banners
&lt;/h3&gt;

&lt;p&gt;The cookie banner is often the first thing a user hits, and often the first barrier. Check that it receives focus or sits first in the tab order, that it can be operated with the keyboard, that its buttons have real text and enough contrast, and that "Reject" is as reachable as "Accept". If it's a modal, it needs the same focus handling as the drawer above.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Form errors
&lt;/h3&gt;

&lt;p&gt;At checkout, a red border alone doesn't tell anyone what went wrong. Tie the error text to the field and announce it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
       &lt;span class="na"&gt;aria-invalid=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;aria-describedby=&lt;/span&gt;&lt;span class="s"&gt;"email-err"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email-err"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Enter an email like name@example.com&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;autocomplete&lt;/code&gt; attributes to address and payment fields too (WCAG 1.3.5). Shopify's hosted checkout handles most of this itself, but custom cart pages, newsletter popups and WooCommerce checkout customisations often don't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why overlays don't solve it
&lt;/h2&gt;

&lt;p&gt;Accessibility widgets that add a toolbar or "AI fixes" with a single script tag are tempting, but they don't change your theme's HTML. They can't reliably write meaningful alt text for your products, fix a focus trap in your drawer's JavaScript, or know what an unlabeled icon button is for. Many disabled users already have their own tools and find overlays get in the way. A widget also doesn't produce the accessibility information the EAA asks you to publish. Fixing the source is less work than it sounds, because most of the issues live in a few theme components.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 30-minute self-audit with free tools
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Minutes 0â€“10: automated scan.&lt;/strong&gt; Install &lt;strong&gt;axe DevTools&lt;/strong&gt; (the free browser extension) and run it on your home page, a collection or category page, a product page and the cart. Then run &lt;strong&gt;Lighthouse&lt;/strong&gt; â†’ Accessibility in Chrome DevTools for a second opinion. Fix the "critical" and "serious" items first. Remember that automated tools catch only part of what WCAG covers, which is why the next steps matter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Minutes 10â€“20: keyboard-only purchase.&lt;/strong&gt; Unplug the mouse. Using only Tab, Shift+Tab, Enter, Space, the arrow keys and Escape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Can you see where focus is at all times?&lt;/li&gt;
&lt;li&gt;[ ] Can you dismiss the cookie banner?&lt;/li&gt;
&lt;li&gt;[ ] Can you open and close the menu, and does Escape work?&lt;/li&gt;
&lt;li&gt;[ ] Can you choose a variant (size or colour) and add the product to the cart?&lt;/li&gt;
&lt;li&gt;[ ] When the cart drawer opens, does focus move into it, and back out when it closes?&lt;/li&gt;
&lt;li&gt;[ ] Can you get through checkout to the payment step?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Minutes 20â€“30: screen reader.&lt;/strong&gt; Use &lt;strong&gt;NVDA&lt;/strong&gt; (free, Windows), &lt;strong&gt;VoiceOver&lt;/strong&gt; (built in on macOS/iOS: Cmd+F5) or &lt;strong&gt;TalkBack&lt;/strong&gt; on Android. On a product page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Do icon buttons announce what they do?&lt;/li&gt;
&lt;li&gt;[ ] Do product images have a sensible description?&lt;/li&gt;
&lt;li&gt;[ ] Are price, variant and stock status announced?&lt;/li&gt;
&lt;li&gt;[ ] Is a form error read out when you submit an empty field?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, zoom to 200% and check that nothing overlaps or disappears. Write down everything you find. That list is your backlog, and it's also the input for the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to put in your accessibility statement
&lt;/h2&gt;

&lt;p&gt;Annex V of the directive requires service providers to publish information on how the service meets the accessibility requirements. It must be available in an accessible format and kept up to date for as long as the service runs. Most stores do this with an "Accessibility" page linked from the footer and the terms. A practical structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What the service is and how it works:&lt;/strong&gt; browsing, cart, checkout, account, customer support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The standard you measure against:&lt;/strong&gt; EN 301 549 / WCAG 2.1 AA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Current status:&lt;/strong&gt; what conforms, plus &lt;strong&gt;known issues&lt;/strong&gt; and when you plan to fix them. Being honest here is better than claiming "fully compliant".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How you keep it compliant:&lt;/strong&gt; when you test, for example after theme updates, and with what.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A contact for accessibility problems&lt;/strong&gt;, plus alternative ways to order, such as phone or email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The national enforcement authority&lt;/strong&gt; customers can turn to (not spelled out in Annex V, but good practice).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The date&lt;/strong&gt; of the last review.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check your country's specific requirements. Some national laws or authorities spell out extra details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The EAA isn't about perfection on day one. It's about not shutting people out of buying from you, and being transparent about where you stand. For most WooCommerce and Shopify stores, the bulk of the work is a few theme components (icon buttons, the cart drawer, the cookie banner, contrast tokens) plus alt text and a statement page. Run the 30-minute audit, fix the critical issues, publish an honest statement, and re-test after every theme update.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm building a small scanner that does this check and drafts the accessibility statement for EU stores. If you want early access or a free scan, there's a waitlist: &lt;a href="https://xfranv8.github.io/escaner-accesibilidad-ue/?ref=devto" rel="noopener noreferrer"&gt;https://xfranv8.github.io/escaner-accesibilidad-ue/?ref=devto&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>ecommerce</category>
      <category>webdev</category>
      <category>wordpress</category>
    </item>
  </channel>
</rss>
