ARIA Roles & Attributes
debt(d4/e5/b5/t7)
Closest to 'default linter catches the common case' (d3) +1. Tools like axe, Lighthouse, WAVE, and eslint-plugin-jsx-a11y can catch many ARIA issues (missing roles, aria-hidden on focusable elements, missing aria-expanded). However, these are specialist accessibility tools rather than default linters, and they catch structural issues but miss behavioral ones (e.g., whether keydown handlers actually work). The gap between what automated tools catch (missing attributes) and what they miss (missing keyboard interaction) pushes this to d4.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix says to prefer native HTML elements over ARIA, but retrofitting proper ARIA onto custom components requires adding keyboard handlers, focus management, and state tracking (aria-expanded, aria-modal, etc.) — not a one-line fix. A single custom dropdown or modal might need significant rework across its template, JS, and styles. If a codebase has many custom components built without ARIA, the effort compounds across multiple files.
Closest to 'persistent productivity tax' (b5). ARIA applies across all web contexts and touches every custom UI component. Once a team commits to building custom components (dropdowns, modals, tabs, sliders), ARIA and its companion keyboard/focus requirements become a persistent tax on every new component and every modification. It's not quite b7 because teams using native HTML elements or component libraries can largely avoid the burden, but for teams with custom component systems it slows down many work streams.
Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception is precisely stated: developers believe adding ARIA attributes makes elements accessible, but ARIA only adds semantics — it does NOT add behavior. A div with role='button' looks like it should work like a button but doesn't respond to Enter/Space without explicit keydown handlers. This directly contradicts the mental model from native HTML where semantic elements provide both semantics AND behavior. The aria-hidden='true' on focusable elements trap is similarly dangerous — it removes from the accessibility tree but keyboard focus still reaches it, the opposite of what developers expect.
Also Known As
TL;DR
Explanation
ARIA (role, aria-label, aria-describedby, aria-expanded, aria-hidden, aria-live) enhances accessibility for non-semantic HTML. The first rule of ARIA: don't use ARIA if native HTML provides the semantics. role='button' on a div is inferior to a real <button>. aria-label provides a text alternative for elements without visible text. aria-expanded signals the open/close state of accordions and dropdowns. aria-hidden='true' removes decorative elements from the accessibility tree. Never remove focus without providing an alternative.
Diagram
flowchart TD
HTML[Semantic HTML<br/>button input nav main] -->|native semantics| ACC[Accessibility Tree]
ARIA[ARIA attributes<br/>role aria-label aria-expanded] -->|supplement| ACC
ACC --> SR[Screen Reader<br/>NVDA JAWS VoiceOver]
subgraph First Rule of ARIA
NATIVE[Use native HTML first<br/>button not div with role=button]
KBRD[Add keyboard handlers<br/>if using role=button on div]
end
BAD[div onclick] -.->|missing keyboard nav| BROKEN[Inaccessible]
GOOD[button type=button] -->|built-in keyboard| WORKS[Accessible]
style BROKEN fill:#f85149,color:#fff
style WORKS fill:#238636,color:#fff
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- role='button' on a div without keyboard handlers — screen reader announces button but Enter/Space don't work.
- aria-hidden='true' on focusable elements — removes from accessibility tree but keyboard can still focus it.
- aria-label on every element — not needed on elements with visible text; use aria-labelledby instead.
- Not updating aria-expanded when opening/closing components — screen reader never announces state changes.
Avoid When
- Using ARIA to replace native HTML elements that already provide correct semantics.
- Adding ARIA attributes without implementing required keyboard interaction and state updates.
- Applying aria-hidden to interactive or focusable elements.
When To Use
- Building custom UI components like modals, dropdowns, tabs, and sliders.
- Enhancing non-semantic HTML where native elements cannot provide required accessibility.
- Communicating dynamic state changes to assistive technologies.
Code Examples
<!-- Custom dropdown — inaccessible:
<div class="dropdown" onclick="toggle()">Menu</div>
<div class="dropdown-items" style="display:none">
<div onclick="select('home')">Home</div> <!-- Not keyboard accessible -->
</div>
<!-- Accessible dropdown with ARIA:
<button
aria-haspopup="true"
aria-expanded="false"
aria-controls="nav-menu"
id="nav-trigger"
>Menu</button>
<ul id="nav-menu" role="menu" hidden>
<li role="none">
<a href="/" role="menuitem">Home</a>
</li>
</ul>
<!-- JS: toggle aria-expanded and hidden; manage focus -->
<!-- Enter/Space/Escape/Arrow keys handled -->