Skip to main content

ARIA Roles

Landmark roles, widget roles, and when to use ARIA vs semantic HTML.

The First Rule of ARIA​

Don't use ARIA. Use semantic HTML first. Custom ARIA implementations require 5–10× more maintenance than native elements and have worse cross-browser support.

<!-- ❌ Avoid: div with ARIA role -->
<div role="button" tabindex="0" onclick="handleClick()">Click me</div>

<!-- ✅ Prefer: native button -->
<button onclick="handleClick()">Click me</button>

Only use ARIA when semantic HTML genuinely cannot achieve the required functionality.

Landmark Roles​

Landmark roles create navigational structure, allowing screen reader users to skip directly to major page sections.

HTML ElementARIA RolePurpose
<header>bannerSite-wide header (top-level only)
<nav>navigationNavigation menus
<main>mainPrimary content (one per page)
<aside>complementarySidebars, supplementary content
<footer>contentinfoSite-wide footer (top-level only)
<section>regionRequires aria-labelledby or aria-label
<article>articleSelf-contained, independently distributable

When multiple landmarks of the same type exist, distinguish them with labels:

<nav aria-label="Primary navigation">...</nav>
<nav aria-label="Footer navigation">...</nav>

Widget Roles​

Widget roles define interactive component behavior for custom UI that native HTML can't express:

<!-- Tab interface -->
<div role="tablist" aria-label="Settings">
<button role="tab" aria-selected="true" aria-controls="panel-general">General</button>
<button role="tab" aria-selected="false" aria-controls="panel-privacy">Privacy</button>
</div>
<div role="tabpanel" id="panel-general" aria-labelledby="tab-general">...</div>

<!-- Custom select/listbox -->
<div role="listbox" aria-label="Choose a color">
<div role="option" aria-selected="true">Blue</div>
<div role="option" aria-selected="false">Red</div>
</div>

<!-- Dialog -->
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">Confirm Delete</h2>
...
</div>

States and Properties​

ARIA properties are mostly static (define relationships), while states change during user interaction.

<!-- Properties (static relationships) -->
<button aria-label="Close dialog">×</button>
<input aria-describedby="hint-id">

<!-- States (dynamic conditions) -->
<button aria-expanded="false" aria-controls="menu">Menu</button>
<input aria-invalid="true" aria-required="true">
<button aria-pressed="false">Mute</button>

Always keep states synchronized with visual changes.

Real-World Impact​

An e-commerce date picker case study showed screen reader users achieving 95% task success after proper ARIA implementation, up from near-zero baseline. The key was using role="dialog" with proper focus management and aria-selected on calendar date cells.

When to Use ARIA (Decision Tree)​

Is there a native HTML element for this?
├── YES → Use native HTML
└── NO → Is the behavior achievable with existing elements + CSS?
├── YES → Use native HTML + CSS
└── NO → Use ARIA roles + keyboard support + state management

Content from Frontend-Master-Prep-Series — 08-accessibility