Criterion 7.1 requires that every interactive component built in JavaScript is keyboard-operable and correctly exposed to assistive technologies. It's the RGAA's broadest criterion: it covers dropdown menus, modals, carousels, tabs, accordions, autocompletes, dynamic carts — anything that reacts without reloading the page.
The 3 questions to ask for each widget
- 01Is it reachable by keyboard (Tab) and operable (Enter / Space)?
- 02Does it announce its role (button, menu, dialog) to the screen reader?
- 03Does it announce its state changes (open/closed, selected, busy)?
If the answer to all three is yes, the component is probably compliant. If one is no, there's a hole — and it's almost always question 1 (the keyboard) or question 3 (the state) that fails.
The founding trap: the clickable div
⚠ The <div onclick> trap
A `<div onclick="...">` is not keyboard-reachable and is not a button to a screen reader. The fix: a native `<button type="button">`, which handles focus, Enter and Space for free. The golden rule: only invent an interactive element if no native HTML element already does the job.
Role, name, state: the ARIA trio
When a native element isn't enough, ARIA fills the gap along three axes. The role (`role="tab"`, `role="dialog"`…) says what the element is. The accessible name (text, `aria-label`, `aria-labelledby`) says what it's for. The state (`aria-expanded`, `aria-selected`, `aria-checked`, `aria-busy`) says what situation it's in. A widget that has a role but no updated state lies to the screen reader.
Standard ARIA patterns
The ARIA Authoring Practices Guide (APG) maintains a catalogue of verified patterns: combobox, dialog, disclosure, listbox, menu, tabs, treeview — with the expected keyboard handling for each. If your component matches a pattern, follow it to the letter, including the expected arrow-key behaviour. Otherwise you'll very likely do worse than with native HTML.
Focus management, the usual blind spot
- →On opening a modal: focus enters the modal and stays trapped inside as long as it's open
- →On closing: focus returns to the element that triggered it
- →After a dynamic action (add to cart): announce the change via an `aria-live` region
- →Never `outline: none` without a replacement focus indicator (that's criterion 10.7)
// Don't reinvent the wheel
Reka UI (used by ComplAudit), Radix Vue, Headless UI: these kits implement the APG patterns (focus, keyboard, ARIA) correctly. In 2026, writing an accessible menu or modal by hand from scratch means exposing yourself to missing at least one of the rules.
Frequently asked questions
Is axe-core enough to validate a JS widget?
No. axe-core detects invalid ARIA attributes and missing roles, but it doesn't know whether your menu is genuinely operable by keyboard or whether the announced state matches reality. Those points need manual testing with a keyboard and a screen reader.
Does everything really have to be keyboard-operable?
Yes: any action achievable with the mouse must be achievable with the keyboard. That's the foundation of criterion 7.1. A hover that reveals information must also be triggerable on keyboard focus.
What's aria-live for?
To announce a dynamic change without moving focus: "Product added to cart", "3 results found". An `aria-live="polite"` region reads the new content as soon as it appears, without interrupting the user.
Check that your dynamic components are properly exposed to screen readers:
→ Run an audit