Accessibility

a11y/state-exposed

Custom toggles, disclosures and selections expose their state (aria-expanded, aria-pressed, aria-checked, aria-selected).

seriousmanualWCAG 4.1.2 · Afe-a11y-aria

Why

When only a CSS class shows that a menu is open or a filter is on, a screen reader user hears the same "button" before and after the click and cannot tell what happened.

Fix

Bind the state attribute to the same variable that drives the class: aria-expanded on a button that shows and hides content, aria-pressed on a toggle button whose label stays the same, aria-checked on role="switch", aria-selected on tabs and options, aria-current="page" on the current navigation link. Prefer native state (<details open>, <input type="checkbox">) when it fits.

Examples

// bad: the state lives only in the class
<button className={open ? 'is-open' : ''} onClick={toggle}>Filters</button>
// good
<button aria-expanded={open} aria-controls="filters" onClick={toggle}>Filters</button>

Sources

Facts

Id
a11y/state-exposed
Severity
serious
Check
manual a person reviews it; the report lists it as a checklist
Applies to
html angular vue svelte astro jsx
WCAG 2.2
4.1.2, level A
Taught by the skill
fe-a11y-aria ARIA, names and live regions
Since version
0.1.0

Rule file on GitHub

Read it in the terminal

npx github:dawidolko/frontend-skills explain a11y/state-exposed