← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

ARIA Roles & Attributes

Frontend HTML5 Intermediate
debt(d4/e5/b5/t7)
d4 Detectability Operational debt — how invisible misuse is to your safety net

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.

e5 Effort Remediation debt — work required to fix once spotted

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.

b5 Burden Structural debt — long-term weight of choosing wrong

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.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

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.

About DEBT scoring →

Also Known As

ARIA aria-label aria-expanded role attribute screen reader

TL;DR

Accessible Rich Internet Applications attributes add semantic meaning to HTML elements for screen readers — supplementing native HTML semantics for custom widgets.

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

Incorrect ARIA usage can make accessibility worse — mismatched roles, missing keyboard support, or wrong states can mislead screen readers.

Common Misconception

Adding ARIA makes an element accessible — ARIA only adds semantics; keyboard interaction and focus management must be implemented separately. A div with role='button' still needs keydown handlers.

Why It Matters

Custom UI components (dropdowns, modals, tabs, sliders) are invisible to screen readers without ARIA — they appear as unannounced content that keyboard users cannot interact with.

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

💡 Note
Shows how ARIA augments semantics but still requires proper keyboard handling and state management.
✗ Vulnerable
<!-- 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>
✓ Fixed
<!-- 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 -->

Added 15 Mar 2026
Edited 28 Mar 2026
Views 84
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 2 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 3 pings F 2 pings S 8 pings S 3 pings M 2 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 1 ping S 1 ping S 1 ping M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 17 Scrapy 17 Perplexity 14 Google 5 Ahrefs 4 Unknown AI 3 PetalBot 3 Claude 1 Bing 1 Meta AI 1
crawler 61 crawler_json 4 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Use native HTML elements before ARIA — a <button> is always better than <div role='button'>; add ARIA only when HTML semantics are insufficient for custom components
📦 Applies To
javascript HTML5 web
🔗 Prerequisites
🔍 Detection Hints
div or span with onClick without role; custom dropdown without aria-expanded; modal without aria-modal and focus trap
Auto-detectable: ✓ Yes axe lighthouse wave eslint-plugin-jsx-a11y
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: Medium Context: File Tests: Update


✓ schema.org compliant