Standards · ARIA
ARIA roles, states, and properties
68 entries from WAI-ARIA 1.2 — 41 roles, 13 states, and 14 properties. Each entry explains what the role or attribute is for, the native HTML element to reach for first (if one exists), and the failures we see when authors reach past the native element.
Roles (41)
Roles tell assistive technology what kind of UI a component is — button, dialog, listbox. Use the native HTML element first; reach for role only when no native element fits.
-
alertLive regionA live region that conveys an urgent, time-sensitive message. Screen readers announce it immediately, interrupting the current speech. Use sparingly — reserve for genuine errors and warnings; misuse causes assistive-tech fatigue.
-
alertdialogWindowA dialog that conveys an urgent message and requires user response. Combines dialog semantics with alert announcement. Use only for destructive confirmations, errors that block further work, or other interruptions that cannot wait.
-
articleDocument structureMarks a self-contained composition that could stand on its own — a blog post, news story, forum reply, or product card. Use the native <article> element first; reach for role="article" only when you cannot use the HTML element.
Native HTML:
<article> -
bannerLandmarkThe site-wide header landmark — typically holds the logo, primary navigation, and search. The top-level <header> element carries this role automatically. Only one banner per page.
Native HTML:
<header> (top-level) -
buttonWidgetMarks an element as a button — a control that triggers an action when activated. Use the native HTML <button> element first; only reach for role="button" on a <div> or <span> when there is no way to use the native element.
Native HTML:
<button> -
checkboxWidgetMarks an element as a two- or three-state checkbox. Use <input type="checkbox"> first; only reach for role="checkbox" when you cannot use the native input — for example when building a tri-state control that must show a mixed value.
Native HTML:
<input type="checkbox"> -
comboboxWidgetMarks a text input paired with a popup list of values — used for autocomplete, type-ahead search, and custom selects. The native <select> element handles the simple single-select case; reach for role="combobox" only when you need filtering, custom rendering, or remote suggestions.
Native HTML:
<select> -
complementaryLandmarkA landmark for content that supports the main content but is meaningful on its own — sidebars, related-article boxes, supplementary callouts. The <aside> element carries this role when it is at the top level.
Native HTML:
<aside> -
contentinfoLandmarkThe site-wide footer landmark — copyright, contact, legal links. The top-level <footer> element carries this role automatically. Only one contentinfo per page.
Native HTML:
<footer> (top-level) -
definitionDocument structureMarks an element as the definition of a term. Pair with role="term" (or native <dfn>) to associate the term with its definition. Use native <dl>/<dt>/<dd> or <dfn> first — they carry the semantics for free.
Native HTML:
<dfn> -
dialogWindowMarks a container as a modal or non-modal dialog. Use the native <dialog> element with showModal() — it handles focus trapping, the top-layer, the backdrop, and Escape-to-close for free. Reach for role="dialog" only when the native element is impossible.
Native HTML:
<dialog> -
figureDocument structureMarks a self-contained illustrative block — image, diagram, code listing — typically paired with a caption. Use the native <figure> element first; reach for role="figure" only when the host element cannot be a <figure>.
Native HTML:
<figure> -
formLandmarkA landmark for a form — a collection of input controls that submit data. A <form> element is exposed as a form landmark ONLY when it has an accessible name. Without a name, it is just a form, not a landmark.
Native HTML:
<form aria-label> -
groupDocument structureMarks a generic grouping of related elements. Less semantically heavy than a landmark — screen readers do not advertise groups in the landmark menu. Use <fieldset> + <legend> for grouped form controls; reach for role="group" for non-form groupings.
Native HTML:
<fieldset> -
headingDocument structureMarks an element as a heading. Use <h1>–<h6> first — they carry the right semantics and a correct level for free. Reach for role="heading" only when you have to upgrade an element that cannot be an <h*>.
Native HTML:
<h1> – <h6> -
linkWidgetMarks an element as a hyperlink — a control that navigates to a new resource when activated. Use the native HTML <a href> element first; only reach for role="link" on a <span> or <div> when there is no way to use the native element.
Native HTML:
<a href> -
listDocument structureMarks an element as a list of items. Use <ul>, <ol>, or <dl> first — native handles the role, the count, and the visual marker. Reach for role="list" only when CSS list-style: none triggers Safari's list-role removal heuristic.
Native HTML:
<ul> / <ol> -
listboxComposite widgetMarks an element as a list of selectable options. Use <select> for the simple single-select case — it gives you a mobile-friendly picker and full keyboard support. Reach for role="listbox" when you need custom styling, multi-select with custom rendering, or pairing with a combobox.
Native HTML:
<select> (single-select) -
listitemDocument structureMarks an element as one item in a list. Use <li> inside <ul> or <ol> — the native element carries the role and the position-in-set. Reach for role="listitem" only when paired with an explicit role="list" on a non-list parent.
Native HTML:
<li> -
mainLandmarkThe main content landmark — the page's primary content, excluding repeated headers, navigation, and footers. The <main> element carries this role automatically. Exactly one main per page.
Native HTML:
<main> -
menuComposite widgetMarks a container as an application menu — the popup of File/Edit-style menus or context menus. There is no HTML equivalent. A site's navigation list is NOT a menu; use <nav> with <ul> of links instead.
-
menubarComposite widgetMarks a container as a persistent menubar — the always-visible horizontal strip of File/Edit/View-style menus seen in desktop apps. Distinct from menu, which is a popup. Almost never the right pattern on the web.
-
menuitemWidgetMarks an element as an actionable item inside a menu or menubar. There is no HTML equivalent — menus are an ARIA-only construct. Use this role only when you are building an actual menu (application-style); a plain navigation list should NOT use menu/menuitem.
-
navigationLandmarkA landmark grouping a set of navigation links — primary nav, breadcrumb, table-of-contents. The <nav> element carries this role automatically. Multiple navs per page are common and fine, but each must have a distinct accessible name.
Native HTML:
<nav> -
optionWidgetMarks an element as a selectable item inside a listbox. An option MUST be a descendant of a listbox (directly, or via aria-owns). Use native <option> inside <select>; reach for role="option" only when building a custom listbox or combobox popup.
Native HTML:
<option> -
progressbarWidgetMarks an element as a progress indicator. Use <progress> first — it ships the semantic, the determinate visual, and the value attributes natively. Reach for role="progressbar" when you must style beyond what the native element allows.
Native HTML:
<progress> -
radioWidgetMarks an element as a single option in a mutually exclusive group. A radio must live inside a radiogroup (or a native fieldset). Use <input type="radio"> first; reach for role="radio" only when the native input is impossible.
Native HTML:
<input type="radio"> -
regionLandmarkA generic landmark for content that doesn't fit banner, main, navigation, complementary, or contentinfo — but is still important enough to navigate to. A <section> becomes a region landmark when, and only when, it has an accessible name.
Native HTML:
<section aria-label> -
searchLandmarkA landmark grouping a search form. Lets screen-reader users jump straight to the site search. The native <search> element (HTML 2024) carries this role automatically; use role="search" on a <form> for broader browser support today.
Native HTML:
<search> -
searchboxWidgetMarks an element as a text input scoped to a search task. Use <input type="search"> first — it provides clear-button affordances on most browsers and the search semantic for free. Reach for role="searchbox" only on a custom contenteditable search field.
Native HTML:
<input type="search"> -
separatorDocument structureMarks an element as a divider between sections of content or items in a composite widget. Use <hr> first for thematic breaks in prose; reach for role="separator" when separating items inside a menu, toolbar, or other widget.
Native HTML:
<hr> -
sliderWidgetMarks an element as an input that selects a value from a range. Use <input type="range"> first; only reach for role="slider" when you need a custom track — for example a two-thumb range picker, which native does not support.
Native HTML:
<input type="range"> -
statusLive regionA live region that conveys non-urgent advisory information. Screen readers announce changes politely — at the next pause in speech, not interrupting. Use for routine confirmations, counts, and progress updates. The native <output> element carries this role.
Native HTML:
<output> -
switchWidgetMarks an element as an on/off switch. Functionally close to a checkbox, but announced as "switch, on" or "switch, off" rather than "checked" — better matches a settings toggle. There is no native HTML equivalent yet.
-
tabWidgetMarks an element as one tab in a tabbed interface. A tab MUST live inside a tablist, and SHOULD reference its associated tabpanel via aria-controls. There is no native HTML tab element — tabs are an ARIA-only pattern.
-
tablistComposite widgetMarks a container as the strip of tabs in a tabbed interface. Holds role="tab" children. Tabs and tabpanels are an ARIA-only pattern — there is no native HTML tablist.
-
tabpanelDocument structureMarks the content panel paired with a tab. Each tabpanel is labelled by its tab via aria-labelledby; the tab references the panel via aria-controls. Show one panel at a time; hide the others with the hidden attribute.
-
textboxWidgetMarks an element as a single- or multi-line text input. Use <input type="text"> or <textarea> first — they handle every textbox behaviour for free. Reach for role="textbox" only when building a rich-text editor on a contenteditable element.
Native HTML:
<input type="text"> / <textarea> -
toolbarDocument structureMarks a container as a toolbar — a grouped set of related controls (a formatting bar, a row of icon buttons). Reduces the tab-stop cost: a toolbar of 10 buttons becomes one tab-stop, with arrow keys to move between buttons.
-
treeComposite widgetMarks an element as a hierarchical container of treeitems — a file explorer, nested categories, or org chart. Single-tab-stop, arrow-key navigation, expand/collapse. There is no native HTML equivalent.
-
treeitemWidgetMarks an element as one item inside a tree. A treeitem can be expandable (a parent of more treeitems) or terminal (a leaf). Use only when building a hierarchical navigator — file explorer, org chart, nested categories — that needs single-tab-stop arrow-key navigation.
States (13)
States change as the user interacts (pressed, checked, expanded, busy). They are dynamic and must be kept in sync with the visible UI.
-
aria-atomicLive-region stateControls whether assistive technology announces a live region's entire contents on update or just the part that changed. Default is "false" (just the diff). Set "true" when context only makes sense as a whole sentence.
-
aria-busyGlobal stateMarks a region as in the middle of an update so assistive technology suppresses interim announcements. Set to "true" while loading or while large DOM changes are in progress; flip back to "false" when the region is stable.
-
aria-checkedWidget stateIndicates the current checked state of a checkbox, radio button, or check-style menu item. Takes "true", "false", or "mixed". The native HTML checkbox manages this for free — only set it manually on custom widgets.
-
aria-currentWidget stateMarks the element that represents the current item in a set — the active page in a nav, the current step in a wizard, today in a date picker. More specific than aria-selected; use it on links and on items where selection isn't the right metaphor.
-
aria-disabledGlobal stateIndicates that a control is perceivable and focusable but does not respond to user input. Prefer the native HTML disabled attribute when available; reach for aria-disabled when you need the element to remain focusable or to receive a tooltip.
-
aria-expandedWidget stateIndicates whether a collapsible element — disclosure button, combobox, menu, treeitem — is currently open. Takes "true" or "false". Typically paired with aria-controls pointing at the region the control opens.
-
aria-hiddenGlobal stateRemoves an element and all its descendants from the accessibility tree. Sighted users still see the element; assistive technology never reaches it. Reserve for decorative content; never apply to a focusable control.
-
aria-invalidWidget stateIndicates that a form control has failed validation. Pair with aria-describedby pointing to the human-readable error message so the screen reader announces both the invalid state and the reason.
-
aria-liveLive-region stateMarks a region whose updates should be announced by assistive technology without moving focus. Pick "polite" for most cases, "assertive" for genuinely urgent updates. The region must be in the DOM at initial render.
-
aria-modalWidget stateTells assistive technology to treat the rest of the page as inert while a dialog is open. Set to "true" on role="dialog" or role="alertdialog". Does not actually make the background inert — pair with the inert attribute or a focus trap.
-
aria-pressedWidget stateIndicates whether a toggle button is currently pressed. Set to "true" when the toggle is on, "false" when off; the assistive technology announces the state alongside the label.
-
aria-readonlyWidget stateIndicates that a form control's value cannot be edited but the control is still operable — focusable, copyable, and submitted with the form. Different from aria-disabled, which makes the control inoperable.
-
aria-selectedWidget stateIndicates that an item inside a single- or multi-select container is currently selected. Used on tab, option, gridcell, treeitem, and similar roles. Distinct from aria-checked (checkbox/radio) and aria-pressed (toggle button).
Properties (14)
Properties describe a relationship or attribute that does not change frequently (labelledby, controls, level, valuemin). Set them once and forget.
-
aria-activedescendantRelationshipOn a composite widget, points to the ID of the descendant that is currently active. DOM focus stays on the container while a virtual focus moves across children. Alternative to roving tabindex for listboxes, comboboxes, and grids.
-
aria-autocompleteWidget stateOn a textbox or combobox, declares what kind of autocompletion the control offers — inline suggestions, a list of options, both, or none. Distinct from the HTML autocomplete attribute, which is about form-field semantics for the browser.
-
aria-controlsRelationshipNames the element or elements whose presence or content this control governs. Common pairings: a tab controls its tabpanel, a disclosure button controls a revealed region. Support across assistive tech is uneven — use sparingly.
-
aria-describedbyRelationshipReferences one or more IDs of elements whose text becomes the extended description of this element. Announced after the accessible name. Use for help text, format hints, and inline error messages.
-
aria-haspopupWidget stateTells assistive tech that activating this control will open a popup, and what kind. Accepts "menu", "listbox", "tree", "grid", "dialog", or "true" / "false". Pair with aria-expanded so AT can also announce whether the popup is open.
-
aria-labelRelationshipProvides an accessible name as a string when no visible text is available. Use only when there is no on-screen label — if visible text exists, prefer aria-labelledby so the spoken name matches what the user sees.
-
aria-labelledbyRelationshipReferences one or more element IDs whose visible text becomes the accessible name of this element. Preferred over aria-label when on-screen text already describes the control.
-
aria-levelWidget stateIndicates the hierarchical level of an element within a structure. Required on role="heading" elements; also used on role="treeitem" and role="listitem" inside nested lists. Integer value, starting at 1.
-
aria-ownsRelationshipDeclares a parent-child relationship in the accessibility tree when the DOM structure does not express it. Reparents the referenced elements as children of this one for AT purposes. A power tool — easy to misuse.
-
aria-posinsetWidget statePosition of an item within a set when the DOM cannot express it — typically because items are virtualized, paginated, or filtered. Always pair with aria-setsize so screen readers can announce "3 of 47".
-
aria-requiredWidget stateIndicates that user input is required on a control before a form can be submitted. Use the HTML required attribute on native form fields; reach for aria-required only when no HTML equivalent exists — e.g. a combobox built on a div.
-
aria-setsizeWidget stateTotal number of items in a set when the DOM does not contain them all. Pairs with aria-posinset so a screen reader can announce "item 14 of 5,000" even if only five are rendered. Use -1 if the total is unknown.
-
aria-sortWidget stateOn a column or row header in a sortable grid or table, announces the current sort direction. Values: "ascending", "descending", "other", or "none". Only one header in the table should carry a sorted value at a time.
-
aria-valuenowWidget stateCurrent numeric value of a range-style widget — slider, progressbar, spinbutton, scrollbar. Pair with aria-valuemin and aria-valuemax so AT can announce a meaningful position. Use aria-valuetext for non-numeric labels.
No ARIA entries match your filters.