When we write well-structured HTML without altering the default behaviors, our websites become naturally accessible.
But sometimes, what we're building requires more complexity.
We might have error messages, live content updates, or other widgets. While these components are great for user experience, they’re far from the original document-based behavior designed for browsers and markup languages.
They need a little help — and that’s where Accessible Rich Internet Applications (ARIA) comes in.
This guide will cover the main features defined in the ARIA specification, when you should (and shouldn’t) use ARIA to supplement your semantic HTML, and how to test your authored ARIA.
How can you get the most out of this post?
Before diving in, you should know or explore the following items. They'll make it easier to understand what ARIA is, as well as when and why you'd use it.
- How to write semantic HTML
- What is web accessibility, and why it's important
- That browsers create an accessibility tree based on the DOM tree, which exposes information about specific elements to assistive technologies via the accessibility API
What is ARIA? Getting familiar with the WAI-ARIA Specification
Written entirely as WAI-ARIA (Web Accessibility Initiative — Accessible Rich Internet Applications), ARIA is a specification defined by the W3C.
This specification outlines roles and attributes designed to change HTML elements' exposed meaning (commonly referred to as “semantics”). Roles define what an element is or does, while attributes affect and describe interactions.
The goal is to help assistive technologies present the content and support interaction in a way that matches expectations.
Using ARIA is particularly valuable for describing elements beyond HTML's current capabilities or lacking full support.
By default, semantic HTML elements have an implicit
role that defines what an element is or does. Available definitions are added to the accessibility tree and later interpreted by a screen reader or another tool.
The HTML tag and the
role are synonymous with some elements, like
<form> and the role
<table> and the
Other elements have roles with complimentary, but not interchangeable, names. Two examples are
<progress>, which has the
progressbar role, and
<hr>, which uses the
However, some elements don’t have implicit roles.
<div>, for instance, both have
generic as their role. In many cases, this value returns
null. This doesn't give someone using assistive technology any context to understand what the element does or why it's on the page.
That’s where ARIA roles can be useful.
ARIA roles are defined in an HTML element using
role=“name”, but replacing
name with a role from the ARIA specification. It works by overriding the element's native role semantics in the accessibility tree.
<div role=“status”>An update for you!</div>
A screen reader will report the element as a status in the proceeding code.
Important note: Roles only change the native role semantics of the host element. They don’t change how the element looks or behaves for people who aren’t using assistive technology (i.e., you'll still be able to press a
<button> even if you add a different ARIA role).
Where to find a list of ARIA roles
A thorough list of the various ARIA roles and role types is available on MDN web docs.
Along with roles, the WAI-ARIA specification provides a set of states and properties (collectively called "attributes") that affect and describe interactions. These attributes are often, but not always, used to support existing ARIA roles on a page.
All ARIA attributes follow the same naming convention, with the state or property name beginning with the string
In the preceding example,
name represents a support state or property.
ARIA properties define the purpose of an HTML element in the accessibility tree or describe the relationship between the host element and other elements on the page.
Once set, properties typically don't change (unlike ARIA states).
One popular property is
aria-label, a string value that labels an interactive element.
aria-label is frequently used to override an existing label with more precise information intended for people using a screen reader.
The following is an example from the Accessibility Developer Guide:
Someone looking at the page built with the preceding code will see a button with text that reads "Zoom image." They can quickly click, check it out, and move on.
But someone using a screen reader may not understand what the button does and what will happen if they interact with it.
aria-label can help fill the gap:
<button aria-label="Zoom image: opens a high-resolution version, press Esc to close"> Zoom image </button>
Using `aria-label` should be a last resort
Generally, semantic HTML elements have a way to provide labels — such as
<label> for inputs,
<caption> for tables, or
alt attributes on
<img> tags. Using
aria-label should be a last resort.
Commonly used ARIA states include
aria-selected, and more.
The following example uses
aria-checked to indicate whether the element is checked (
true) or unchecked (
<ul> <li> <div role="checkbox" aria-checked="false"> Ketchup </div> </li> <li> <div role="checkbox" aria-checked="true"> Mustard </div> </li> </ul>
The element with the current checked state signifies our preferred condiment ("Mustard" in the preceding code).
An overview of available ARIA attributes sorted by category is available on MDN web docs.
Knowing when not to use ARIA
“No ARIA is better than Bad ARIA” is a common saying in the accessibility community. It’s even at the top of the ”Read Me First” page in the W3C’s ARIA Authoring Practices Guide (APG).
Because ARIA can cover up an element’s original semantics or content, it gives a lot of power to the developer writing it. So websites with incorrectly implemented ARIA might override native accessibility semantics, which can cause more issues than websites without ARIA.
The following example (adapted from the APG) shows the potential danger:
<!-- 🚨 Invalid HTML --> <ul role=“navigation”> <!-- This is a navigation region, not a list. --> <li><a href=“/”>Home</a></li> <li><a href=“/about”>About</a></li> <li><a href=“/contact>Contact</a></li> <!-- Error! Previous list items are not in a list. --> </ul>
🚧 Important note: Even though it’s invalid, this HTML will render and visually look like a list (browsers are very forgiving). That’s why it’s essential to test and validate your HTML and authored ARIA.
In the preceding code, we override the
<ul> tag’s native
list role by using ARIA to define
role="navigation" on the element.
navigation is a landmark role, meaning it provides a way to identify the structure of a webpage— not recognize list items. And because the ARIA role is prioritized over the native semantics by the accessibility tree, changing this role invalidates our HTML.
Instead of changing the role, we can nest a list inside of navigation using semantic HTML (no ARIA needed):
<!-- ✅ Valid HTML --> <nav> <ul> <li><a href=“/”>Home</a></li> <li><a href=“/about”>About</a></li> <li><a href=“/contact>Contact</a></li> <ul> </nav>
More accessible navigation samples, including popup menus, are in Heydon Pickering’s “Building Accessible Menu Systems” article in Smashing Magazine.
If you’re feeling overwhelmed by this power, there are a couple of questions to help ensure your ARIA is more helpful than harmful:
Is there a native HTML element or attribute I can use?
According to the W3C, this is the first rule of ARIA use:
"If you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so.”
Let’s look at a button.
The following shows what the W3C refers to as a “redundant role”:
<!-- Avoid doing this 🙅🏼♀️ --> <button role=“button”>Interact with me!</button>
Specifying this role is unnecessary, as the
<button> already has the
button role. Fortunately, adding this role probably won’t have any unexpected side effects beyond more verbose markup.
Where you run into problems is if you try to build a button using a generic element like a
<!-- Avoid doing this 🙅🏼♀️ --> <div role=“button”>Interact with me!</div> <!-- Do this instead 🙋🏼♀️ --> <button>Interact with me!</button>
Native elements have built-in keyboard accessibility, roles, and states. When you use ARIA instead, you also take responsibility for mimicking these behaviors.
Does the ARIA I’m authoring change the native semantics of this element?
The second rule of ARIA use: If you need to use ARIA, try to avoid changing native semantics.
The W3C uses the example of wanting to build a heading that’s a tab:
<!-- Don’t do this 🙅🏼♀️ --> <h2 role=“tab”>Important tab</h2>
If you need to change the semantics, consider swapping the host element for one with the role you want. From there, you can nest your other elements.
For the preceding code, that means replacing the
<h2> (which has a
heading role) with a generic, non-semantic tag where you can add the
tab role. Then, nest your heading:
<!-- Do this instead 🙋🏼♀️ --> <div role=“tab”> <h2> Important tab </h2> </div>
If you want to write accessible tabs, Inclusive Components' Tabbed Interfaces is a solid reference.
Pattern guides for common components
The APG also includes a comprehensive collection of interactive component pattern guides. They cover commonly built and headache-inducing components, such as accordions, modals, sliders, tooltips, and many more.
These guides describe the pattern and provide an example. Each example page contains the following:
- Accessibility features list
- Any necessary keyboard support
- Table of the ARIA features used
- All source code (and a CodePen link)
Testing your authored ARIA
Browsers do their best to render something passable on the page, even if the underlying HTML isn't valid. Just because everything looks visually correct doesn't automatically mean it's accessible.
You're going to want to test what you wrote, and the following are just a few ways to do that:
Your mileage may vary
Many ARIA features aren't fully supported in modern browsers. Beyond browsers, feature support can change based on the operating system, assistive technology, and more. That's part of what makes native semantic HTML elements more reliable.
If you need to use ARIA, websites like Accessibility Support can help you identify potential issues.