Accessibility
ARIA
Accessible Rich Internet Applications
Intermediate
a11y aria screen-readers wcag
Definition
ARIA (Accessible Rich Internet Applications) is a set of attributes that define ways to make web content and web applications more accessible to people with disabilities. ARIA supplements HTML’s native semantics to provide additional information to assistive technologies.
Core ARIA Concepts
Roles
<!-- Define what an element is or does -->
<div role="button" tabindex="0">Click me</div>
<nav role="navigation">...</nav>
<div role="alert" aria-live="assertive">
Error: Form submission failed
</div>
Properties
<!-- Describe characteristics -->
<button aria-expanded="false">Menu</button>
<input aria-required="true" />
<div aria-hidden="true">Decorative icon</div>
States
<!-- Dynamic values that change -->
<button aria-pressed="false">Toggle</button>
<div role="checkbox" aria-checked="mixed">Select all</div>
<div aria-busy="true">Loading...</div>
Common ARIA Patterns
Navigation
<nav aria-label="Main navigation">
<ul>
<li><a href="/" aria-current="page">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<nav aria-label="Breadcrumb">
<ol>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li aria-current="page">Product Name</li>
</ol>
</nav>
Custom Buttons
<!-- When you can't use native button -->
<div
role="button"
tabindex="0"
aria-pressed="false"
onclick="toggle()"
onkeydown="handleKey(event)"
>
Play
</div>
<script>
function handleKey(event) {
// Enter or Space activates button
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
toggle();
}
}
</script>
Modal Dialog
<div
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
aria-describedby="dialog-desc"
>
<h2 id="dialog-title">Confirm Delete</h2>
<p id="dialog-desc">Are you sure?</p>
<button>Cancel</button>
<button>Delete</button>
</div>
Live Regions
<!-- Announce dynamic content changes -->
<div aria-live="polite" aria-atomic="true">
<span id="status">3 items in cart</span>
</div>
<script>
// Screen reader announces when text changes
document.getElementById('status').textContent = '4 items in cart';
</script>
<!-- Assertive (interrupts) -->
<div aria-live="assertive" role="alert">
Session expired. Please log in again.
</div>
Form Enhancements
Label Association
<!-- Explicit labeling -->
<label for="email">Email Address</label>
<input type="email" id="email" />
<!-- Implicit labeling -->
<label>
Email Address
<input type="email" />
</label>
<!-- ARIA labeling (when label isn't visible) -->
<input
type="search"
aria-label="Search products"
placeholder="Search..."
/>
Error Messages
<label for="username">Username</label>
<input
type="text"
id="username"
aria-invalid="true"
aria-describedby="username-error"
/>
<span id="username-error" role="alert">
Username must be at least 3 characters
</span>
Required Fields
<label for="email">
Email
<span aria-label="required">*</span>
</label>
<input type="email" id="email" required aria-required="true" />
Complex Widgets
Tabs
<div class="tabs">
<div role="tablist" aria-label="Settings">
<button
role="tab"
aria-selected="true"
aria-controls="panel-1"
id="tab-1"
>
General
</button>
<button
role="tab"
aria-selected="false"
aria-controls="panel-2"
id="tab-2"
tabindex="-1"
>
Privacy
</button>
</div>
<div
role="tabpanel"
id="panel-1"
aria-labelledby="tab-1"
>
General settings content
</div>
<div
role="tabpanel"
id="panel-2"
aria-labelledby="tab-2"
hidden
>
Privacy settings content
</div>
</div>
Accordion
<div class="accordion">
<h3>
<button
aria-expanded="false"
aria-controls="section1"
id="accordion1"
>
Section 1
</button>
</h3>
<div
id="section1"
role="region"
aria-labelledby="accordion1"
hidden
>
<p>Section 1 content</p>
</div>
</div>
ARIA Rules
First Rule: Use Native HTML
<!-- Don't do this -->
<div role="button" tabindex="0" onclick="...">Click</div>
<!-- Do this instead -->
<button onclick="...">Click</button>
Don’t Change Native Semantics
<!-- Wrong -->
<h2 role="tab">Heading</h2>
<!-- Correct -->
<div role="tab"><h2>Heading</h2></div>
All Interactive ARIA Controls Must Be Keyboard Accessible
// Add keyboard support for custom controls
element.addEventListener('keydown', (e) => {
switch(e.key) {
case 'Enter':
case ' ':
// Activate
break;
case 'ArrowDown':
// Next item
break;
case 'ArrowUp':
// Previous item
break;
case 'Escape':
// Close/Cancel
break;
}
});
Common Mistakes
<!-- ❌ Redundant ARIA -->
<button role="button">Click</button>
<!-- ❌ Conflicting ARIA -->
<h1 role="presentation">Title</h1>
<!-- ❌ Missing labels -->
<input type="text" placeholder="Search" />
<!-- ❌ aria-hidden on focusable element -->
<button aria-hidden="true">Click</button>
<!-- ✅ Correct usage -->
<button>Click</button>
<input type="text" aria-label="Search" placeholder="Search" />
Key Takeaway
ARIA enhances accessibility when native HTML semantics aren’t sufficient. Prefer native HTML elements first, then use ARIA to fill gaps. Remember that ARIA only affects the accessibility tree - you must still implement keyboard support and visual styling. Test with actual screen readers, and follow the ARIA Authoring Practices Guide for complex patterns.