ARIA Roles
A role tells assistive technology what an element is. "This is a button." "This is a navigation area." "This is a tab." It is the first thing a screen reader tells you about something, and it decides how a person expects to use it: a button is pressed, a checkbox is toggled, a link is followed.
The key point, which you met in the last lesson, is that native HTML elements already have roles. A button is a button, a nav is a navigation landmark, an h2 is a level 2 heading. The role attribute is for the situations where HTML has no element that fits.
What You Will Learnβ
- What a role is, and how native elements already have them
- The main families of roles: landmark, widget, live region, structure, and window
- Which roles are worth knowing
- What a role promises, and what you must still build
- Roles to avoid
- How to check roles
The Big Ideaβ
- HTML Code
- Role Explorer
<!-- Native elements already have roles -->
<header>β¦</header> <!-- role: banner -->
<nav aria-label="Main">β¦</nav> <!-- role: navigation -->
<main>β¦</main> <!-- role: main -->
<button type="button">Save</button> <!-- role: button -->
<h2>Ingredients</h2> <!-- role: heading, level 2 -->
<!-- An explicit role fills a gap: there is no HTML tab element -->
<div role="tablist" aria-label="Recipe">
<button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1">
Ingredients
</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">β¦</div>
<!-- A live region needs a role too -->
<div role="status">Recipe saved.</div>
35 roles shown. Choose one to see the details.
button (Widget)
Native HTML: button
Needs a name: Required
Keyboard: Enter and Space
Something you press to do an action.
<button type="button">Save</button>This is a selection of the most useful roles, not the whole list. For a custom widget, always follow a tested pattern, because a role also brings rules about names, keyboard keys, required children, and states.
Browse the list by category, search for an element such as nav, and look at the "Native HTML" line first. Most of the time it says an element exists.
How Roles Workβ
- Every element has a role, either implicit (from the HTML element) or explicit (from the
roleattribute). - An explicit role wins over the implicit one.
<div role="button">is a button to assistive technology, even though it is adivin the code. - A role is a promise. It tells people what to expect: a
buttonshould respond to Enter and Space, atabshould respond to arrow keys, adialogshould keep focus inside. The role does not keep the promise for you. You must write the behaviour. - Each role has rules. Some need a name (
dialog,img), some need children of a certain kind (tablistneedstab,listneedslistitem), and some need states (checkboxneedsaria-checkedif it is custom). - A role needs to fit the element. The "ARIA in HTML" rules list which roles are allowed on which elements. For example, you may not put
role="button"on a heading, or on a link, without changing what the element is. - The
roleattribute can hold a list of words, and browsers use the first one they understand. It is rarely needed, and support is not something to rely on, so use one role. - Roles are read by the browser's accessibility tree, which you saw in Introduction to Accessibility.
The Families of Rolesβ
| Family | What it covers | Examples |
|---|---|---|
| Landmark | Big areas of the page | banner, navigation, main, search, contentinfo |
| Widget | Things you interact with | button, checkbox, tab, slider, combobox |
| Live region | Messages that change | status, alert, log, timer |
| Document structure | The shape of content | list, heading, img, table, group |
| Window | Pop-up windows | dialog, alertdialog |
There is also a group of abstract roles used to define the others. Never use them in your pages.
Landmark Rolesβ
Landmarks mark the big areas of a page. Screen reader users can list them, or jump between them, much as sighted users glance at the layout. They are the single biggest help for people who need to get to the main content, the search box, or the menu without reading everything in order.
You almost never need the role attribute for them, because HTML elements do the job:
| Element | Landmark role |
|---|---|
header (directly in the page) | banner |
nav | navigation |
main | main |
aside | complementary |
footer (directly in the page) | contentinfo |
section (with a name) | region |
form (with a name) | form |
search, or form role="search" | search |
Rules of thumb:
- One
mainper page, and useheaderandfooterfor the page (not for sections). - Name repeated landmarks, with
aria-labeloraria-labelledby: twonavelements need different names. - Do not repeat the role in the name: "Main," not "Main navigation."
- Use
sectionandregionsparingly. Too many landmarks are as unhelpful as none. - Put everything inside a landmark. Content outside any landmark is easy to miss.
- A newer
searchelement exists in recent HTML. Support is growing, so check your target browsers, and userole="search"on a form as the safe option.
- HTML Code
- Landmark Lab
<header>β¦</header>
<nav aria-label="Main">β¦</nav>
<form role="search" aria-label="Recipes">
<input type="search" aria-label="Search recipes">
<button type="submit">Search</button>
</form>
<main>
<h1>Sourdough</h1>
β¦
</main>
<aside aria-label="Related recipes">β¦</aside>
<nav aria-label="Footer links">β¦</nav>
<footer>β¦</footer>
The HTML:
<header>β¦</header>
<nav aria-label="Main">β¦</nav>
<form role="search" aria-label="Recipes">β¦</form>
<main>
</main>
<aside aria-label="Related recipes">β¦</aside>
<nav>β¦</nav>
<footer>β¦</footer>
A screen reader's landmark list:
- banner
- navigation: Main
- navigation
- search: Recipes
- main
- complementary: Related recipes
- contentinfo
- Problem: Two navigation landmarks, and one has no name. Someone browsing landmarks cannot tell them apart.
Screen readers can list the landmarks of a page, or jump from one to the next, so people can skip straight to the main content or the search. The names and the list shown here are a simplified example of that, and each screen reader words it a little differently. Also note that the header and footer are page-level landmarks only when they sit directly in the page, and not inside an article or section.
Widget Rolesβ
Widget roles describe interactive things. Native elements cover many of them (button, checkbox, radio, textbox, slider, progressbar, option). A few have no native element, so you need roles to build them: tab, tablist, tabpanel, switch, menu, menuitem, tooltip, and a full combobox.
Using a widget role is a contract. It means you will provide:
- A name.
- The right states (for example
aria-selectedon a tab). - The keyboard behaviour people expect (arrow keys inside tabs and menus).
- Focus handling (a roving
tabindexin a tab list, for instance). - The right structure (tabs inside a tablist).
If you cannot provide all five, do not use the role. A half-built widget confuses people more than a plain one.
menu is not for website navigation. A role="menu" tells a screen reader to switch into a special mode where the arrow keys are the way to move, like an application menu. A site's main menu is a list of links, so use nav, ul, and a.
Live Region Rolesβ
Some roles tell assistive technology to announce changes to a region, without moving focus. The page must already contain the region, and then you change the text in it.
| Role | Announced | Use it for |
|---|---|---|
status | Politely (when the reader is free) | "Recipe saved," "3 results found" |
alert | At once, and may interrupt | Urgent errors, "Session ending" |
log | Politely, new items added | Chat, activity history |
timer | Not announced as it changes | A countdown, with a name |
Try them in the lab. If you use a screen reader, you will hear the real thing.
role="status" (polite)
role="alert" (assertive)
role="log" (a history)
What a screen reader would do (simulation):
Press a button.
These are real live regions, so if you use a screen reader, you will hear them. The list above is only a plain-text simulation of the difference. Two things matter: the region must already be in the page before its text changes, and an identical message is not announced again. The exact behaviour depends on the screen reader and browser, so test it. Do not use alert for ordinary messages, because it interrupts people.
Choose the gentlest option that works. Most messages should be status, and alert should be rare. Over-using alert is like shouting: it interrupts people, and makes them stop trusting your messages. The next lessons cover live regions in depth, in aria-live.
Structure and Special Rolesβ
Most structure roles come from HTML: ul and ol (list), li (listitem), h1 to h6 (heading), table, img, figure, hr (separator), article. A few explicit roles are worth knowing:
role="img"makes a group of things (an SVG, a few emoji) read as one image, with a name fromaria-label.role="group"with a name gathers related controls, such as a set of toolbar buttons. For form fields, preferfieldsetandlegend.role="presentation"orrole="none"removes the role of an element. It is useful to turn a layout table into plain content, or to hide aliinside a custom widget. Never put it on something focusable or interactive.role="list"on aulwithlist-style: none. Some browser and screen reader combinations (notably Safari with VoiceOver) have stopped treating such a list as a list. Adding the role puts it back. This behaviour has changed over time, so check what your audience's browsers do before adding it everywhere.
Roles to Avoidβ
- Abstract roles (such as
widget,landmark,command). They are only for the ARIA specification. role="application". It tells screen readers to hand over all the keys to your page, and turn off their own navigation. Almost no page needs it.role="menu"for site navigation. Use anavwith links.- A role that repeats the element:
<button role="button">,<nav role="navigation">. It does nothing useful, and clutters your code. - A role that fights the element:
<h2 role="button">,<a role="heading">. Wrap the content instead:<h2><button>β¦</button></h2>. role="alert"for everyday messages.- Interactive roles with no keyboard support (see Accessible Buttons).
- Roles you do not understand. If you cannot say what a role promises, do not use it.
Check Your Rolesβ
- Open the Accessibility panel in your browser's DevTools, and look at the Role of each element. Does it match what you intended?
- List the landmarks with a screen reader, or a browser extension that shows them. Is there one
main? Are repeated ones named? - Search your code for
role=. For each one, ask: is there a native element? Is the role allowed on this element? Do I provide the name, states, and keys that go with it? - Run an automated checker (axe, Lighthouse) for invalid roles, missing required children, and missing names.
- Use the keyboard on every widget role, and listen with a screen reader.
- Check the "ARIA in HTML" rules if you are unsure which roles an element may have.
Good Habitsβ
- Use the element with the right role, and add
roleonly to fill a gap. - Use landmark elements, and name the repeated ones.
- Treat a widget role as a promise of name, states, keys, and focus.
- Follow a tested pattern for tabs, menus, combo boxes, and dialogs.
- Choose
statusbeforealert. - Never put
presentation,none, oraria-hiddenon focusable elements. - Keep roles in line with the real behaviour.
- Test with a screen reader, and review roles in code review.
Accessibility Checklistβ
- No role is used where a native element does the job.
- The page has one
main, and aheaderandfooter. - Repeated landmarks have unique names.
- Every widget role has a name, the right states, and the right keyboard behaviour.
- Required parent and child roles are present (such as
tablistwithtab). -
dialogandalertdialoghave names, and move focus in and out. -
statusis used for normal messages, andalertis rare. -
menuis not used for site navigation, andapplicationis not used. - No focusable element has
role="presentation"orrole="none". - Roles do not repeat or fight the element they are on.
Security and Privacy Notesβ
- Do not announce sensitive data in live regions. A
statusoralertthat reads out an account number, a one-time code, or a password can be overheard. - Do not use roles to disguise controls. A control that looks harmless but is announced as something else, or the other way round, is a deceptive pattern, and can hide dangerous actions from people who cannot see the screen.
- Alerts must be honest. A fake "Security warning" in an
alertrole, used to push people into clicking, is a scam technique. - Be careful with user-supplied text in roles and ARIA values. Never insert unchecked user input into attributes.
- Role-based detection of screen reader users (by looking for how they use landmarks or live regions) could reveal a disability. Avoid tracking it.
- Dialogs that ask for consent or privacy choices need proper roles and focus, so that everyone can answer. Hidden or hard-to-reach "reject" buttons are a dark pattern.
Global Audience Notesβ
- Landmark names are text, so translate them (
aria-label="Main",aria-label="Footer links") along with the rest of the page. - Do not repeat the role name in your label. Screen readers say "navigation" in the user's own language, so "Main navigation" can become a repeated word after translation.
- Set
langon the page, and on any labels in other languages. - Right-to-left languages: arrow-key behaviour in tabs, menus, and toolbars should follow the reading direction. Test it.
- Live regions in other languages: make sure the message text is in the page's language, and short enough to be understood when read aloud.
- Different devices: many people use a screen reader on a phone. Roles are understood there too, but some patterns (such as menus and combo boxes) behave differently on touch. Test on mobile.
Common Mistakes to Avoidβ
div role="button"with no keyboard support.role="button"on abutton, orrole="navigation"on anav.- A
sectionwith no name, expected to be a landmark. - Two
navelements with no names. role="menu"for a site navigation.role="application""to be safe."role="alert"for every message.- A
tablistwith notabchildren. role="presentation"on something focusable.- Landmarks nested or repeated without reason.
- Content outside any landmark.
- Never checking the roles in the Accessibility panel.
Practice Timeβ
Try these in your browser and your editor:
- Browse the role explorer, and find the native element for ten roles.
- Use the landmark lab to build a page with no problems, and then break it one way at a time.
- Open a page you built, and list its landmarks with a screen reader or an extension.
- Add names to two
navelements, and check the Accessibility panel. - Change a layout table to
role="presentation", and compare it with using CSS grid. - Use the live roles lab with a screen reader (if you can), and compare
statuswithalert. - Replace three
div role="button"elements with real buttons. - Make a
role="img"SVG, with a short name. - Search your project for
role=, and mark each as "native exists," "fills a gap," or "not sure." - Bonus: read the tabs pattern in the ARIA Authoring Practices Guide, and list the roles, states, and keys it needs.
Quick Recapβ
Click a question to check your answer.
1. What is a role?
It tells assistive technology what an element is, such as a button, a navigation area, or a tab, and so how a person should expect to use it.
2. What is the difference between an implicit and an explicit role?
An implicit role comes from the HTML element (a nav is a navigation). An explicit role is set with the role attribute, and it wins over the implicit one.
3. Does adding role="tab" to a button make it behave like a tab?
No. The role is a promise. You must add the states (aria-selected), the keyboard behaviour (arrow keys), and the focus handling yourself.
4. Why name two nav landmarks differently?
So a person browsing the landmark list can tell them apart, for example "Main" and "Footer links."
5. When should you use role="status" and when role="alert"?
Use status for ordinary updates, announced politely. Use alert rarely, for urgent messages that must be announced at once.
6. Why is role="menu" wrong for site navigation?
It switches screen readers to an application-style mode with arrow-key navigation. A website menu is a list of links, so use nav, ul, and a.
Key Takeawaysβ
- A role says what something is. Native elements already have the right ones.
- Landmark elements (
header,nav,main,aside,footer) are the easiest big win. Name the repeated ones. - A widget role is a promise of a name, states, keys, and focus. Keep it, or do not use the role.
- Live regions need a role, and must already exist in the page. Prefer
status, and usealertrarely. - Avoid abstract roles,
application,menufor navigation, and roles that repeat or fight the element. - Never put
presentation,none, oraria-hiddenon focusable elements. - Check roles in the Accessibility panel, and test with a screen reader.
Next, learn how to describe what things are doing with ARIA States and Properties.