The European Accessibility Act: What Frontend Developers Actually Need to Do

Photo by AbsolutVision on Unsplash

The EAA isn’t a vague legal idea anymore — it’s enforceable law, and regulators across the EU are already issuing warnings and opening investigations. This tutorial skips the legal jargon and gets straight to what matters to you: the specific things to check on your website, why they matter, and exactly how to fix them — whether you’re patching an existing site or building a new one from scratch.

📋 Table of Contents

  1. What the EAA Actually Requires (No Legal Jargon)
  2. Does This Apply to Your Website?
  3. The Standard You’re Actually Building Against: WCAG 2.1 AA
  4. Issue 1 — Keyboard Navigation Gaps
  5. Issue 2 — Missing or Bad Alt Text
  6. Issue 3 — Poor Color Contrast
  7. Issue 4 — Forms Without Proper Labels
  8. Issue 5 — Broken Heading Structure
  9. Issue 6 — Custom Components Missing ARIA
  10. Issue 7 — No Visible Focus Indicator
  11. Issue 8 — Inaccessible Error Messages
  12. Issue 9 — Videos Without Captions
  13. Issue 10 — Reflow & Zoom Failures
  14. The Accessibility Statement You Must Publish
  15. Where to Start: A Priority Roadmap
  16. Testing Workflow for Ongoing Compliance
  17. FAQ

What the EAA Actually Requires (No Legal Jargon)

Let’s cut through the legal language. The European Accessibility Act says: if you sell digital products or services to consumers in the EU, your website and apps need to be usable by people with disabilities — people who can’t see a screen well, can’t use a mouse, can’t hear audio, or process information differently.

It came into force on 28 June 2025. It’s enforced separately by each of the 27 EU member states, which means the exact fine amounts and enforcement style differ a bit by country — but the technical bar you need to clear is the same everywhere, because they all point back to the same standard.

Here’s the part that matters most to you as a developer: the EAA doesn’t invent new technical rules. It points to an existing, well-documented standard — EN 301 549 — which is built on top of WCAG 2.1 Level AA, a standard you can actually learn, test against, and build to. That’s good news. You don’t need to guess what “accessible” means; there’s a checklist.


Does This Apply to Your Website?

Before diving into fixes, it’s worth a quick gut-check on scope. You don’t need a lawyer for this — the lines are fairly clear for most everyday websites:

Your situationEAA scope?Notes
E-commerce site selling to EU consumersIn scopeEven if your company is based outside the EU
Banking, payments, or fintech appIn scopeExplicitly named in the Act
Travel/transport booking platformIn scopeTicketing and journey info both covered
Telecom or ISP customer portalIn scopeIncludes account management interfaces
E-book or digital publishing platformIn scopeCovers reading apps and the content format itself
Pure B2B SaaS, no consumer signupLikely out of scopeEAA targets consumer-facing services
Microenterprise (under 10 staff, <€2M turnover)Partial exemptionExempt from service rules, not product rules
Internal company tools / intranetOut of scopeNot offered to consumers
Archived content not updated since before 28 Jun 2025Mostly exemptUpdating it brings it back into scope
💡
If you’re unsure, the safer engineering default is to build accessibly anyway. The line between “in scope” and “out of scope” is a business/legal decision above your pay grade as a developer — but the cost of building accessibly from the start is far lower than retrofitting later, regardless of which side of the line you land on.

The Standard You’re Actually Building Against: WCAG 2.1 AA

When people say “EN 301 549 compliance,” what they mean in practice — for the parts of the site you build — is WCAG 2.1 Level AA. This is the version most EU regulators are checking against today, even though a future revision is expected to point to WCAG 2.2. Building to 2.2 now is a smart hedge, since it’s a superset of 2.1 with a handful of extra rules.

WCAG organizes everything around four principles, often remembered as POUR:

  • Perceivable — can people sense the content, regardless of which sense they’re missing? (alt text, captions, contrast)
  • Operable — can people navigate and interact, regardless of input method? (keyboard, no flashing, enough time)
  • Understandable — is the content and interface predictable and clear? (labels, error messages, consistent navigation)
  • Robust — does it work reliably with assistive technology? (valid HTML, correct ARIA)

Now let’s get into the actual issues. These ten cover the overwhelming majority of what regulators are flagging in real EAA enforcement cases so far — checkout flows, search, forms, and homepage navigation.

1. Keyboard Navigation Gaps

WCAG 2.1.1 (A) · 2.1.2 (A) · 2.4.7 (AA)

Why it matters: Around 1 in 14 people use a keyboard instead of a mouse to browse the web — due to motor impairments, screen reader use, or simply personal preference. If any part of your site only responds to mouse clicks or hover, those users hit a wall. This is one of the very first things accessibility auditors test, because it takes 30 seconds: unplug the mouse and press Tab.

The fix

Almost every keyboard issue traces back to one root cause: using a non-interactive element (a <div> or <span>) styled to look like a button, instead of an actual <button> or <a>. Native elements get keyboard support for free — your job is to stop reinventing them.

<div class="btn" onclick="submitForm()">
  Submit
</div>

/* Tab skips right over this.
   Enter/Space do nothing. */
<button type="button" class="btn" onclick="submitForm()">
  Submit
</button>

/* Tab focuses it.
   Enter and Space both activate it.
   No extra JS required. */

If you genuinely must use a <div> for a custom widget (rare — think drag handles, custom sliders), you need to manually replicate what the browser gives buttons for free:

<div
  class="custom-btn"
  role="button"
  tabindex="0"
  id="custom-submit"
>Submit</div>

// You must add keyboard handling manually — buttons get this for free
document.getElementById('custom-submit').addEventListener('keydown', (e) => {
  if (e.key === 'Enter' || e.key === ' ') {
    e.preventDefault(); // stop page scroll on Space
    submitForm();
  }
});

// 👆 Honestly — just use <button> instead and skip all of this.
  • 01Replace clickable <div>/<span> elements with <button> or <a href="...">
  • 02Test your entire checkout/signup flow with the mouse unplugged — Tab, Shift+Tab, Enter, Space, Esc
  • 03Check for “keyboard traps” — modals or widgets where Tab gets stuck and can’t escape
  • 04Make sure the Tab order follows the visual reading order, not the DOM order if they differ (avoid tabindex values above 0)

2. Missing or Bad Alt Text

WCAG 1.1.1 (A)

Why it matters: Screen reader users hear “image” with no further information when alt text is missing. For e-commerce specifically — exactly the sector EAA targets first — this means a blind shopper literally cannot tell what a product looks like or whether they’re looking at the right item.

The fix

The test to apply: “If this image disappeared, what information would the sighted user lose?” That answer is your alt text. Not a generic label, not the filename — the actual missing information.

<img src="prod-4471.jpg" alt="image">
<img src="logo.png" alt="logo.png">
<img src="chart.png" alt=""> 
<!-- (chart has real data — shouldn't be empty) -->
<img src="prod-4471.jpg" 
     alt="Navy wool peacoat, double-breasted, front view">

<a href="/">
  <img src="logo.png" alt="Acme — return to homepage">
</a>

<img src="chart.png" 
     alt="Revenue grew from €40K in Jan to €98K in June 2025">
  • 01Informative images (product photos, charts, diagrams) → describe the content/meaning
  • 02Functional images (logo-as-link, icon buttons) → describe the action, not the image
  • 03Decorative images (dividers, background flourishes) → use alt="" so screen readers skip them entirely — this is correct, not lazy
  • 04For complex data visualizations, put the long description in nearby visible text or a <figcaption>, not crammed into the alt attribute

3. Poor Color Contrast

WCAG 1.4.3 (AA) · 1.4.1 (A)

Why it matters: This is the single most common accessibility failure on the web — appearing on the vast majority of homepages scanned in annual accessibility surveys. Low-contrast text is unreadable for people with low vision, color blindness, or anyone using their phone in bright sunlight. It’s also the cheapest fix on this entire list.

The fix

WCAG AA requires a contrast ratio of 4.5:1 for normal text and 3:1 for large text (24px+, or 19px+ bold) against its background. You don’t need to calculate this by eye — use a tool.

/* ❌ Light grey on white — ratio ~2.85:1, fails AA */
.muted-text { color: #999999; background: #ffffff; }

/* ✅ Darker grey — ratio 4.6:1, passes AA */
.muted-text { color: #5c6675; background: #ffffff; }

/* ❌ Placeholder text often defaults to very low contrast */
input::placeholder { color: #cccccc; }

/* ✅ Bump it up — placeholders still need 4.5:1 */
input::placeholder { color: #767676; }

CSS prop=”prop” hint: color property name above renders correctly in the code block; just flagging for clarity since this is a text-only response.

  • 01Install the free Colour Contrast Analyser (TPGi) or use the contrast checker built into Chrome DevTools’ color picker
  • 02Check body text, placeholder text, disabled-but-still-readable states, and text over images/gradients — these get missed most often
  • 03Never rely on color alone to show state (e.g., a red border for errors) — pair it with an icon or text label too (WCAG 1.4.1)
  • 04Run axe DevTools across your key pages — contrast failures are flagged automatically and precisely

4. Forms Without Proper Labels

WCAG 1.3.1 (A) · 3.3.2 (A) · 4.1.2 (A)

Why it matters: Checkout, signup, and login forms are exactly what Sweden’s and the Netherlands’ regulators announced they’re prioritizing in their first compliance reviews. A form input with only a placeholder — no real label — is invisible to a screen reader once the user starts typing, because placeholders disappear.

The fix

Every input needs a real, programmatically connected <label>. The connection is made with matching for and id attributes — this is non-negotiable, not optional polish.

<input 
  type="email" 
  placeholder="Email address"
>

<!-- Disappears on focus.
     No screen reader announcement.
     Low contrast by default. -->
<label for="email">Email address</label>
<input 
  type="email" 
  id="email" 
  name="email"
  autocomplete="email"
>

<!-- Always visible.
     Announced correctly.
     Clicking the label focuses the input. -->
  • 01Audit every form on your site — checkout, signup, login, newsletter, search — for missing <label> elements
  • 02Group related fields (like a set of radio buttons) inside <fieldset> with a <legend>
  • 03Add autocomplete attributes (name, email, tel, street-address) — this helps users with motor and cognitive disabilities specifically, and it’s an explicit WCAG criterion (1.3.5)
  • 04Never use a CAPTCHA as the only way to verify a human — WCAG 3.3.8 requires an accessible alternative

5. Broken Heading Structure

WCAG 1.3.1 (A) · 2.4.6 (AA)

Why it matters: Screen reader users frequently jump between headings as a way of skimming a page — similar to how a sighted person scans visually for the section they want. If your headings skip levels or are chosen purely for font size rather than structure, that navigation breaks completely.

The fix

Headings exist to describe document structure, not to make text bigger. If you want bigger text without semantic meaning, use CSS — not a heading tag.

<h1>Product Name</h1>
<h4>Description</h4>   <!-- skipped h2, h3 -->
<h2>Reviews</h2>       <!-- now out of order -->
<h5>Related items</h5> <!-- skipped again -->
<h1>Product Name</h1>
  <h2>Description</h2>
  <h2>Reviews</h2>
    <h3>Most helpful</h3>
  <h2>Related items</h2>

/* Style with CSS, not by jumping heading levels */
  • 01Exactly one <h1> per page
  • 02Never skip a level going down (h2 → h4 is wrong; h2 → h3 is right)
  • 03Use browser extensions like “HeadingsMap” to visualize your page’s outline and spot gaps instantly
  • 04Add landmark regions too — <nav>, <main>, <footer> — these let screen reader users jump straight to a section without reading headings at all

6. Custom Components Missing ARIA

WCAG 4.1.2 (A)

Why it matters: Modern frontends are full of custom-built dropdowns, modals, tabs, and accordions. None of these are native HTML elements, so the browser gives them zero built-in accessibility — you have to add it. Without it, a screen reader user has no idea a dropdown opened, a tab switched, or a modal appeared.

The fix

The golden rule of ARIA: use it to describe state, not to replace good HTML. A real <button> with aria-expanded beats a <div role="button"> every time.

<h3>
  <button
    type="button"
    aria-expanded="false"
    aria-controls="shipping-panel"
    id="shipping-header"
  >
    Shipping & Returns
  </button>
</h3>
<div
  id="shipping-panel"
  role="region"
  aria-labelledby="shipping-header"
  hidden
>
  <!-- panel content -->
</div>

// JS: toggle aria-expanded AND the hidden attribute together
button.addEventListener('click', () => {
  const expanded = button.getAttribute('aria-expanded') === 'true';
  button.setAttribute('aria-expanded', !expanded);
  panel.hidden = expanded;
});
  • 01Modals need role="dialog", aria-modal="true", a focus trap, and Escape-to-close
  • 02Dropdowns/menus need aria-expanded on the trigger and arrow-key navigation between options
  • 03Live updates (cart count, search results, form errors) need aria-live="polite" so screen readers announce the change automatically
  • 04Run every custom component past axe DevTools — incorrect ARIA usage is one of the easiest things for automated tools to catch

7. No Visible Focus Indicator

WCAG 2.4.7 (AA) · 2.4.11 (AA, new in 2.2)

Why it matters: If a keyboard user can’t see where focus currently is, keyboard navigation is technically possible but practically useless — they’re navigating blind. This is shockingly common because outline: none is a popular “quick fix” for designers who don’t like the default blue outline.

The fix

Never remove the focus outline without replacing it with something equally visible. The modern best practice uses :focus-visible, which shows the indicator for keyboard users but hides it for mouse clicks — giving you the best of both worlds.

/* ❌ NEVER do this site-wide */
*:focus { outline: none; }

/* ✅ Hide for mouse clicks, keep for keyboard navigation */
*:focus:not(:focus-visible) { outline: none; }

*:focus-visible {
  outline: 3px solid #0b5fff;
  outline-offset: 3px;
  border-radius: 3px;
}
  • 01Search your entire CSS codebase for outline: none or outline: 0 and verify each one has a :focus-visible replacement
  • 02Make sure the focus indicator has enough contrast against its background (same 3:1 ratio rules apply)
  • 03Test on dark-themed sections separately — a dark blue outline can vanish on a dark background

8. Inaccessible Error Messages

WCAG 3.3.1 (A) · 3.3.3 (AA) · 4.1.3 (AA)

Why it matters: Checkout form validation is one of the highest-friction moments in any user journey, and it’s exactly where regulators have been testing. If errors are only shown as a red border with no text, or appear visually but aren’t announced to screen readers, those users are stuck — they know something’s wrong but not what or where.

The fix

Every error needs three things: it must be visibledescribed in text (not color alone), and announced to assistive technology when it appears dynamically.

<label for="card-number">Card number</label>
<input
  type="text"
  id="card-number"
  aria-invalid="true"
  aria-describedby="card-error"
>
<p id="card-error" role="alert">
  <span aria-hidden="true">⚠</span>
  Card number must be 16 digits.
</p>

// role="alert" makes screen readers announce this
// the moment it appears in the DOM — no extra JS needed
  • 01Pair every error with an icon or text label — never rely on a red border alone
  • 02Connect the error message to its input using aria-describedby
  • 03Set aria-invalid="true" on the input while it has an error
  • 04For a top-of-form error summary on submit, use role="alert" or aria-live="assertive" so it’s announced immediately

9. Videos Without Captions

WCAG 1.2.2 (A) · 1.2.1 (A)

Why it matters: Captions aren’t just for deaf and hard-of-hearing users — they’re used constantly by people watching with sound off in public, non-native speakers, and anyone in a noisy environment. The EAA specifically calls out media accessibility as a requirement for sectors like travel, telecoms, and digital publishing.

The fix

For pre-recorded video, captions are achievable with native HTML — no special player required.

<video controls>
  <source src="product-demo.mp4" type="video/mp4">
  <track
    kind="captions"
    src="captions-en.vtt"
    srclang="en"
    label="English"
    default
  >
</video>
  • 01Add a .vtt caption file for every pre-recorded video using the native <track> element
  • 02For purely visual videos (no dialogue but important visual info), provide an audio description or a text transcript
  • 03If you embed third-party video (YouTube, Vimeo), confirm captions are enabled and accurate — auto-generated captions often need manual correction
  • 04Never autoplay audio — if you must autoplay video, mute it by default and give an obvious unmute control

10. Reflow & Zoom Failures

WCAG 1.4.10 (AA) · 1.4.4 (AA)

Why it matters: Many low-vision users browse with their browser zoomed to 200–400%. If your layout breaks, overlaps, or requires horizontal scrolling at that zoom level, the site becomes unusable for them — even though “technically” nothing crashed.

The fix

This usually comes down to fixed pixel widths and a layout that doesn’t use responsive units. Test by zooming your browser to 400% (Ctrl/Cmd + + several times) and checking for horizontal scrollbars or overlapping elements.

/* ❌ Fixed width breaks at high zoom */
.product-grid { width: 1200px; }

/* ✅ Responsive width with a sensible max */
.product-grid {
  width: 100%;
  max-width: 1200px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

/* ✅ Fluid type scales smoothly instead of breaking layout at fixed breakpoints */
h1 { font-size: clamp(1.5rem, 4vw, 2.5rem); }
  • 01Replace fixed-pixel container widths with %, max-width, and CSS Grid/Flexbox
  • 02Use relative units (rem, em, clamp()) for font sizes so they scale with browser zoom and user font preferences
  • 03Test your three most important pages at 400% zoom in actual Chrome/Firefox — not just DevTools device emulation
  • 04Make sure text can be resized up to 200% without assistive technology and without loss of content or function (WCAG 1.4.4)

The Accessibility Statement You Must Publish

This part isn’t code, but it’s a hard EAA requirement and frontend developers are often the ones who end up building the page for it. Every in-scope service provider must publish a public-facing accessibility statement describing how the service complies — or where it currently falls short.

📄
Your accessibility statement should include: a description of how the service meets the requirements, a way for users to contact you about accessibility barriers, and the name of the relevant enforcement authority where users can file a complaint if your response is inadequate. Treat this as a living document — update it as you fix issues, don’t just publish it once and forget it.

Where to Start: A Priority Roadmap

You can’t fix everything in a day, and you shouldn’t try to. Here’s how to sequence the work for maximum impact with limited time — this mirrors what EU regulators themselves are checking first.

Critical — Week 1

Checkout & account flows

Keyboard navigation, form labels, and error messages on signup, login, and checkout. This is exactly what French, Swedish, and Dutch regulators are checking first.

Critical — Week 1

Color contrast sweep

Run axe DevTools across your top 10 pages. Contrast fixes are pure CSS — fast to fix, zero risk, immediate impact.

High — Week 2-3

Alt text audit on product/content pages

Especially for e-commerce — product images need real, descriptive alt text, not filenames or “image”.

High — Week 2-3

Heading structure & landmarks

Run HeadingsMap across your site. Fixing heading hierarchy is usually just changing tag names — low risk, high reward.

Medium — Month 2

Custom component ARIA review

Modals, dropdowns, tabs, carousels. Higher effort since it often needs JS changes, not just markup.

Medium — Month 2

Video captions & reflow testing

Caption files for existing video library; 400% zoom test across key templates.


Testing Workflow for Ongoing Compliance

Compliance isn’t a one-time audit you check off — new features can reintroduce old problems. Build a layered testing habit:

  • 1
    Automated scan on every PR: wire axe-core into your CI pipeline so accessibility regressions get caught before merge, the same way you’d catch a broken unit test.
  • 2
    Manual keyboard pass on new features: before marking any ticket “done,” tab through the new UI once. It takes under a minute and catches the most common failure on this entire list.
  • 3
    Screen reader spot-check monthly: NVDA (free, Windows) or VoiceOver (built into Mac/iOS) on your three most-used flows.
  • 4
    Real user testing periodically: automated tools catch roughly a third of issues — actual users with disabilities will surface things no tool can.

Frequently Asked Questions

Does the European Accessibility Act apply to my website?

If you sell products or services to consumers in the EU — e-commerce, banking, transport ticketing, telecoms, e-books, or related digital services — you are very likely in scope, regardless of where your company is based. Pure B2B services and microenterprises (fewer than 10 employees and under €2 million turnover) have partial exemptions, but consumer-facing platforms generally must comply.

What accessibility standard do I need to meet for EAA compliance?

The EAA does not name a single technical standard directly, but compliance is generally demonstrated through EN 301 549, the European ICT accessibility standard, which currently incorporates WCAG 2.1 Level AA. Building to WCAG 2.2 AA is a sensible forward-looking target, since a future revision of EN 301 549 is expected to reference it.

What happens if my website is not compliant?

Enforcement is handled by national authorities in each EU member state, and penalties vary by country. Most authorities are currently favoring warnings and a remediation period over immediate fines, but persistent non-compliance can lead to financial penalties, corrective orders, or restricted market access. Disability advocacy groups in several countries have also begun filing complaints and legal proceedings directly against non-compliant companies.

Do existing websites need to comply immediately?

Services already on the market before 28 June 2025 generally have until 28 June 2030 to fully comply, or sooner if the service undergoes a substantial update. New websites and services launched after 28 June 2025 must comply immediately. Either way, starting remediation now reduces both legal risk and the eventual cost of the work.

Where should a frontend developer start with EAA compliance?

Start with an automated scan using axe DevTools or Lighthouse to catch the easier 30–40% of issues, then manually test keyboard navigation and screen reader compatibility on your core user flows — search, checkout, account creation, and forms — since these are the areas EU regulators have explicitly said they are checking first.


Your EAA Action Plan

The European Accessibility Act turned “we should probably get to accessibility eventually” into a real deadline with real consequences. The good news: the technical bar is well-defined, well-documented, and entirely achievable with focused effort — there’s no ambiguity about what “accessible enough” means.

  • This week: Run axe DevTools across your five highest-traffic pages and fix every contrast and missing-label issue it finds — these are quick, low-risk wins.
  • This month: Tab through your entire checkout and signup flow with the mouse unplugged. Fix anything that doesn’t respond to keyboard input.
  • This quarter: Wire axe-core into your CI pipeline so new code can’t quietly reintroduce old problems.
  • Ongoing: Publish (and actually maintain) your accessibility statement, and schedule a recurring screen reader test on your core flows.

None of this requires reinventing your stack. It requires attention, the right testing habits, and treating accessibility as a standard part of “done” — the same way you already treat performance or security.


Posted

in

,

by

Advertisement