This is a searchable reference for WAI-ARIA roles — the role tokens that describe what an element is to assistive technology. It groups them into landmark roles (page regions), document-structure roles (lists, tables, headings), widget roles (buttons, checkboxes, comboboxes, tabs) and live-region roles (alerts and status messages), and for each shows the attributes or context it requires and where its accessible name comes from.
How roles work
A role is applied with the role attribute and tells the accessibility tree how to expose an element. Most native HTML elements already carry an implicit role — <button> is button, <nav> is navigation — so you rarely need to set role explicitly. When you build a custom widget from generic elements, the role brings obligations: many roles require specific attributes (a checkbox needs aria-checked, a slider needs aria-valuenow/aria-valuemin/aria-valuemax, a heading needs aria-level) and composite roles require a child contract (a tablist must own tab children). The name-from column captures how the element’s accessible name is computed: some roles derive it from their text contents, while others require an explicit aria-label, aria-labelledby or associated <label>.
Role categories at a glance
Landmark roles
Landmarks mark out the major navigable regions of a page. Screen-reader users can jump between them with a single keystroke, so using them correctly is high-impact for keyboard navigation:
| Role | Native HTML equivalent | Notes |
|---|---|---|
banner | <header> (when direct child of <body>) | Page-level header; one per page |
navigation | <nav> | Label with aria-label when multiple exist |
main | <main> | One per page; primary content |
complementary | <aside> | Related but secondary content |
contentinfo | <footer> (when direct child of <body>) | Site-level footer |
search | <search> (HTML 5.2+) | Wrap search forms in this |
region | <section> with an accessible name | Requires a label to be exposed as a landmark |
Widget roles (selected)
| Role | Required attributes | Key behaviour to implement |
|---|---|---|
button | None (name required) | Enter and Space activate; toggle with aria-pressed |
checkbox | aria-checked | Space toggles; tristate uses "mixed" |
combobox | aria-expanded, aria-controls | Connects to a listbox or grid popup |
slider | aria-valuenow, aria-valuemin, aria-valuemax | Arrow keys change value |
switch | aria-checked | Same as checkbox but semantically on/off |
tablist → tab → tabpanel | aria-selected, aria-controls | Arrow keys move between tabs |
Live-region roles
Live regions cause screen readers to automatically announce dynamic content changes:
alert— assertive; interrupts the current reading. Use only for time-sensitive errors or warnings. Maps toaria-live="assertive".status— polite; waits for user to finish. Suitable for form success messages. Maps toaria-live="polite".log— for chronological content like chat; polite by default.timer— for countdown or elapsed-time displays; usually has no implicit live behaviour (setaria-livemanually).
Practical examples
<!-- Native is better than ARIA -->
<button type="button">Save</button>
<!-- A custom toggle switch done correctly -->
<span role="switch" tabindex="0" aria-checked="false" aria-label="Dark mode">
</span>
<!-- Tab panel pattern (simplified) -->
<div role="tablist" aria-label="Settings sections">
<button role="tab" aria-selected="true" aria-controls="panel-general" id="tab-general">General</button>
<button role="tab" aria-selected="false" aria-controls="panel-privacy" id="tab-privacy">Privacy</button>
</div>
<div role="tabpanel" id="panel-general" aria-labelledby="tab-general">...</div>
<div role="tabpanel" id="panel-privacy" aria-labelledby="tab-privacy" hidden>...</div>
<!-- Alert for form errors -->
<div role="alert">Your session has expired. Please save your work.</div>
Common pitfalls
- Not managing focus — adding
role="dialog"does not move focus into the dialog. You must do that in JavaScript when the dialog opens. - Nested interactive roles — putting a
buttoninside alinkor nestingtablistinsidetablistcreates invalid hierarchies. - Using
role="presentation"on functional elements — this strips semantics but does not prevent interaction, leaving keyboard users with unlabelled focusable elements. - Repeated landmarks without labels — two
<nav>elements on the same page both expose asnavigation; usearia-labelto distinguish them (“Main navigation” vs “Footer navigation”).
Everything runs in your browser; nothing you search is uploaded.