What the EAA actually requires from a React site
React is accessibility-neutral, so under the EAA the compliance obligation is entirely about your component patterns and, critically, the fact that a client-rendered SPA ships a near-empty HTML shell until JavaScript executes. EN 301 549 conformance forces you to fix hand-rolled modals, tabs, and comboboxes that re-implement keyboard behaviour incorrectly, div-based role="button" elements missing onKeyDown handlers, and SPA route changes that never announce to assistive tech. For a pure client-side React app the requirement effectively demands correct focus management and live-region announcements that a server-rendered site would get more easily.
React underpins a very wide range of products, from small internal-facing tools to large consumer SPAs, so the fine exposure depends heavily on whether the specific app is a consumer-facing service in EU markets. A funded B2C SPA faces the full weight of national penalties, including turnover-percentage regimes for larger operators, while a small startup's app faces fixed per-breach fines. The client-render architecture adds a subtle risk: if the initial payload is inaccessible, an automated audit of the served HTML can flag the whole app as failing before any interaction is even tested.
The pragmatic React fix is to stop hand-rolling interactive widgets and adopt a vetted primitives library (Radix, React Aria, Headless UI) that ships focus trapping, Esc handling, and ARIA for free, which the component team can swap in incrementally. Add an SPA route announcer, wire eslint-plugin-jsx-a11y and @axe-core/react into development, and use the Storybook a11y addon for per-component checks. This is engineering work measured in sprints for a large app, but individual widget swaps are quick wins that remove whole classes of failures at once.
Top WCAG failures we see on React sites
Across hundreds of React scans, the same handful of issues show up over and over. None of them require ripping the theme apart — most are fixable in a few hours by someone comfortable in the platform's editor or template files.
- Custom modals without focus trap or restore2.4.3, 2.1.2 — Level A
Hand-rolled <div> modals usually skip Tab cycling and never restore focus to the trigger. Use a vetted library (Radix, React Aria, Headless UI).
- Click-only ARIA roles2.1.1, 4.1.2 — Level A
role="button" on a <div> needs onKeyDown for Enter and Space. Most teams forget the keyboard half.
- SPA route changes are silent4.1.3 — Level AA
react-router and react-navigation do not notify assistive tech when the URL changes.
Concrete code fixes for React
Below are copy-paste fixes for the most common React issues. They assume you have access to your theme code or the platform's custom-code injection panel. If you cannot edit code directly, share these snippets with whoever maintains the site — every one of them is a ten-minute change.
Use a primitives library instead of hand-rolled modals
import * as Dialog from '@radix-ui/react-dialog';
export function MyModal() {
return (
<Dialog.Root>
<Dialog.Trigger>Open</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title>Title</Dialog.Title>
<Dialog.Close>Close</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}Radix, React Aria, and Headless UI ship with focus trap, Esc handling, and ARIA roles. Free accessibility wins, no implementation cost.
Tools and plugins worth installing first
- eslint-plugin-jsx-a11y
- @axe-core/react in development
- Storybook a11y addon for per-component checks
How to scan a React site without missing anything
Automated scanners catch about 30–40% of WCAG issues; the rest need manual review. The good news is that the 30–40% includes the most expensive issues to remediate after the fact, so an automated scan is the cheapest way to get unstuck. Run one before you change a line of theme code.
- Run scans against the production bundle, not development. Hot reload can mask issues.
Run a free public scan against any React URL right now — no signup, results in 60 seconds.
Frequently asked questions
Do I need React Aria specifically?
Any vetted primitives library will do. The point is not to re-implement focus management and ARIA from scratch.