ARIA Roles
Categories: Accessibility & Inclusive Design, Front-End Development
Definition
ARIA roles are a fundamental component of the Web Accessibility Initiative's Accessible Rich Internet Applications (WAI-ARIA) specification. They define what an element is or does in a web page by providing semantic meaning to elements that might otherwise lack it. ARIA roles are implemented using the role
attribute in HTML and are particularly important for assistive technology users, as they communicate the purpose and function of elements to screen readers and other assistive technologies.
ARIA roles enable developers to create more accessible web experiences by:
- Extending native HTML semantics for custom elements
- Fixing accessibility issues when native HTML semantics are unavailable or cannot be used
- Communicating state, property, and relationship information to assistive technologies
Unlike native HTML semantics, ARIA roles do not change how elements look or behave in browsers—they only affect how elements are interpreted by assistive technologies. In web development, it's important to remember that ARIA should only be used when native HTML semantics cannot provide the necessary accessibility information.
Role Categories
The WAI-ARIA specification organizes roles into several distinct categories:
1. Landmark Roles
Landmark roles identify large, navigable regions of a page, helping users of assistive technologies to navigate and understand the structure of web content.
Examples include:
role="banner"
: Primary header content (typically the site header)role="navigation"
: Collection of navigational elementsrole="main"
: Main content of the documentrole="complementary"
: Supporting content for the main contentrole="search"
: Search functionalityrole="form"
: Region containing a formrole="contentinfo"
: Information about the parent document (typically the footer)
<header role="banner">
<h1>Company Name</h1>
</header>
<nav role="navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
</ul>
</nav>
<main role="main">
<h2>Welcome to our website</h2>
<p>Main content goes here.</p>
</main>
<aside role="complementary">
<h3>Related Information</h3>
<p>Additional content related to the main content.</p>
</aside>
<footer role="contentinfo">
<p>Copyright © 2023</p>
</footer>
Note: Many landmark roles have HTML5 semantic equivalents (<header>
, <nav>
, <main>
, etc.) that should be used instead when possible. The ARIA landmarks are primarily needed for backward compatibility or when semantic HTML elements cannot be used.
2. Document Structure Roles
Document structure roles describe the structural purpose of elements within a document that are not landmarks.
Examples include:
role="article"
: Self-contained composition (article, blog post, etc.)role="definition"
: Definition of a termrole="directory"
: List of references to members of a grouprole="list"
androle="listitem"
: List and list item elementsrole="region"
: Perceivable section containing content relevant to a specific purposerole="heading"
witharia-level
: Heading for a section
<div role="article">
<h2>Blog Post Title</h2>
<p>Content of the blog post...</p>
</div>
<dl>
<dt>HTML</dt>
<dd role="definition">HyperText Markup Language is the standard markup language for documents designed to be displayed in a web browser.</dd>
</dl>
3. Widget Roles
Widget roles define interactive elements that are common in user interfaces but might not have direct HTML equivalents.
Examples include:
role="button"
: Clickable buttonrole="checkbox"
: Checkable inputrole="tablist"
,role="tab"
,role="tabpanel"
: Tab interfacerole="combobox"
: Combo box inputrole="menu"
,role="menuitem"
: Menu interfacerole="dialog"
androle="alertdialog"
: Dialog boxesrole="tooltip"
: Contextual popup providing additional information
<div role="tablist">
<div id="tab1" role="tab" aria-selected="true" aria-controls="panel1">Tab 1</div>
<div id="tab2" role="tab" aria-selected="false" aria-controls="panel2">Tab 2</div>
</div>
<div id="panel1" role="tabpanel" aria-labelledby="tab1">
<p>Content for Tab 1</p>
</div>
<div id="panel2" role="tabpanel" aria-labelledby="tab2" hidden>
<p>Content for Tab 2</p>
</div>
4. Live Region Roles
Live region roles indicate sections of a page that are likely to change dynamically, allowing assistive technologies to announce updates.
Examples include:
role="alert"
: Important, time-sensitive informationrole="log"
: Chat logs, error logs, etc.role="marquee"
: Scrolling informationrole="status"
: Status information updated in response to user actionsrole="timer"
: Countdown or elapsed time display
<div role="alert">
Your session will expire in 5 minutes.
</div>
<div role="status" aria-live="polite">
Form successfully submitted.
</div>
<div role="log" aria-live="polite">
<p>User1: Hello everyone!</p>
<p>User2: Hi there!</p>
</div>
5. Abstract Roles
Abstract roles are the foundation for other roles and should not be used directly in HTML code. They form the taxonomy upon which the role model is built.
Examples include:
role="command"
role="composite"
role="input"
role="landmark"
role="range"
role="section"
role="widget"
Implementation Best Practices
When implementing ARIA roles, follow these best practices to ensure maximum accessibility:
1. HTML First
Always prefer native HTML elements with built-in semantics over ARIA roles when possible. This approach is often referred to as the "first rule of ARIA":
If you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of repurposing an element and adding an ARIA role, state or property to make it accessible, then do so.
For example, use <button>
instead of <div role="button">
, or <nav>
instead of <div role="navigation">
.
2. Match Semantics with Behavior
When using ARIA roles, ensure the element's behavior matches the semantic role you've assigned. If you use role="button"
, the element must:
- Be focusable (using
tabindex="0"
) - Respond to both mouse clicks and keyboard interactions (Enter and Space)
- Be properly labeled for assistive technologies
<div role="button" tabindex="0" aria-pressed="false" onclick="toggleButton(this)" onkeydown="handleKeydown(event, this)">
Toggle Setting
</div>
<script>
function toggleButton(el) {
const isPressed = el.getAttribute('aria-pressed') === 'true';
el.setAttribute('aria-pressed', !isPressed);
// Additional logic...
}
function handleKeydown(event, el) {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
toggleButton(el);
}
}
</script>
3. Use Role-Specific ARIA Attributes
Many ARIA roles have associated states and properties that should be used together with the role for complete accessibility.
For example:
role="checkbox"
requiresaria-checked
role="tab"
works witharia-selected
andaria-controls
role="combobox"
needs attributes likearia-expanded
andaria-controls
<div role="checkbox" aria-checked="false" tabindex="0">
Accept terms and conditions
</div>
4. Maintain Accessible Names
Ensure all interactive elements with ARIA roles have accessible names that assistive technologies can announce. Use:
- Visible text content inside the element
aria-label
for invisible labelsaria-labelledby
to reference another element as the label
<!-- Using element content -->
<div role="button">Submit Form</div>
<!-- Using aria-label -->
<div role="button" aria-label="Close dialog">✕</div>
<!-- Using aria-labelledby -->
<h2 id="dialogTitle">Confirm Deletion</h2>
<div role="dialog" aria-labelledby="dialogTitle">
<!-- Dialog content -->
</div>
5. Update ARIA States Dynamically
When the state of a component changes due to user interaction, update the relevant ARIA attributes to reflect the new state.
// When a tab is activated:
function activateTab(tabId) {
// Deactivate all tabs
document.querySelectorAll('[role="tab"]').forEach(tab => {
tab.setAttribute('aria-selected', 'false');
document.getElementById(tab.getAttribute('aria-controls')).hidden = true;
});
// Activate selected tab
const selectedTab = document.getElementById(tabId);
selectedTab.setAttribute('aria-selected', 'true');
document.getElementById(selectedTab.getAttribute('aria-controls')).hidden = false;
}
Common ARIA Role Patterns
Here are some common UI patterns and the appropriate ARIA roles for implementing them:
Tabs
<div class="tabs-container">
<div role="tablist" aria-label="Content tabs">
<button id="tab1" role="tab" aria-selected="true" aria-controls="panel1">Tab 1</button>
<button id="tab2" role="tab" aria-selected="false" aria-controls="panel2">Tab 2</button>
</div>
<div id="panel1" role="tabpanel" aria-labelledby="tab1">
<p>Content for tab 1</p>
</div>
<div id="panel2" role="tabpanel" aria-labelledby="tab2" hidden>
<p>Content for tab 2</p>
</div>
</div>
Accordion
<div class="accordion">
<h3>
<button id="accordion1" aria-expanded="true" aria-controls="sect1">
Section 1
</button>
</h3>
<div id="sect1" role="region" aria-labelledby="accordion1">
<p>Content for section 1.</p>
</div>
<h3>
<button id="accordion2" aria-expanded="false" aria-controls="sect2">
Section 2
</button>
</h3>
<div id="sect2" role="region" aria-labelledby="accordion2" hidden>
<p>Content for section 2.</p>
</div>
</div>
Modal Dialog
<div id="modalOverlay" role="presentation" aria-hidden="true" hidden>
<div role="dialog" aria-labelledby="dialogTitle" aria-describedby="dialogDesc" aria-modal="true">
<h2 id="dialogTitle">Confirmation</h2>
<p id="dialogDesc">Are you sure you want to delete this item?</p>
<div class="dialog-buttons">
<button>Cancel</button>
<button>Delete</button>
</div>
</div>
</div>
Menu
<div role="menubar" aria-label="Main Menu">
<div role="menuitem" tabindex="0" aria-haspopup="true" aria-expanded="false">
File
<div role="menu" hidden>
<div role="menuitem" tabindex="-1">New</div>
<div role="menuitem" tabindex="-1">Open</div>
<div role="menuitem" tabindex="-1">Save</div>
</div>
</div>
<div role="menuitem" tabindex="0" aria-haspopup="true" aria-expanded="false">
Edit
<div role="menu" hidden>
<div role="menuitem" tabindex="-1">Cut</div>
<div role="menuitem" tabindex="-1">Copy</div>
<div role="menuitem" tabindex="-1">Paste</div>
</div>
</div>
</div>
Common Pitfalls and Errors
Avoid these common errors when implementing ARIA roles:
1. Redundant Roles
Applying ARIA roles that duplicate the semantics of HTML elements.
<!-- Incorrect: Redundant role -->
<button role="button">Submit</button>
<!-- Correct -->
<button>Submit</button>
2. Incorrect Role Usage
Using roles in ways that don't match their intended purpose.
<!-- Incorrect: Misused role -->
<ul role="navigation">
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
<!-- Correct -->
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
3. Missing Required Attributes
Not including required attributes for certain roles.
<!-- Incorrect: Missing required attributes -->
<div role="checkbox">Accept terms</div>
<!-- Correct -->
<div role="checkbox" aria-checked="false" tabindex="0">Accept terms</div>
4. Static ARIA Attributes
Not updating ARIA attributes when the interface state changes.
<!-- Incorrect: Static aria-expanded value -->
<button aria-expanded="false" onclick="toggleMenu()">Menu</button>
<!-- Correct approach in JavaScript -->
function toggleMenu() {
const menuButton = document.getElementById('menuButton');
const isExpanded = menuButton.getAttribute('aria-expanded') === 'true';
menuButton.setAttribute('aria-expanded', !isExpanded);
// Toggle menu visibility...
}
5. Overusing ARIA
Adding unnecessary ARIA roles and attributes when native HTML semantics would suffice.
<!-- Incorrect: Overusing ARIA -->
<div role="heading" aria-level="2">Section Title</div>
<!-- Correct -->
<h2>Section Title</h2>
Testing ARIA Roles
To ensure proper implementation of ARIA roles, use a combination of:
1. Automated Testing
Tools like:
- Axe DevTools
- Lighthouse
- WAVE
- HTML_CodeSniffer
These tools can identify basic issues such as missing required attributes or invalid role values.
2. Manual Testing with Assistive Technologies
- Screen readers: Test with popular screen readers like NVDA, JAWS, or VoiceOver
- Keyboard navigation: Ensure all interactive elements can be accessed and operated with a keyboard
- Visual inspection: Check that visual states match programmatic states
3. Testing Checklist
- Verify each role has all required attributes
- Check that interactive elements are keyboard accessible
- Ensure dynamic updates properly modify ARIA attributes
- Confirm that accessible names are clear and descriptive
- Test the page with screen reader navigation to validate proper announcement
Related Concepts
ARIA States and Properties
In addition to roles, ARIA includes states and properties that provide additional information about elements:
- States: Attributes that change during interaction (e.g.,
aria-checked
,aria-expanded
) - Properties: Attributes that typically remain unchanged (e.g.,
aria-label
,aria-controls
)
Accessible Name Calculation
How browsers and assistive technologies determine the accessible name of an element:
aria-labelledby
(highest priority)aria-label
- Element content
title
attribute (lowest priority)
Focus Management
Proper keyboard focus handling is essential when implementing custom widgets with ARIA roles:
- Managing focus order (
tabindex
) - Containing focus within composite widgets like dialogs
- Restoring focus when components close
Conclusion
ARIA roles are a powerful tool for enhancing web accessibility, particularly for custom components and dynamic content. When used correctly—respecting the "HTML first" principle and ensuring behavior matches semantics—they significantly improve the experience for users of assistive technologies.
However, ARIA roles are not a substitute for building with accessible design principles from the start. The most effective approach to web accessibility combines semantic HTML, appropriate ARIA usage, and thorough testing with assistive technologies to ensure all users can perceive, understand, navigate, and interact with web content.
By understanding and properly implementing ARIA roles, developers can create more inclusive web experiences that work for everyone, regardless of how they access the web.