Skip to content
WCAG & standards

Using ARIA Correctly: Roles, States, Live Regions

WAI-ARIA in practice: roles vs. native HTML, states like aria-expanded and aria-selected, live regions with polite and assertive plus common mistakes.

13 min read ARIAWCAGScreenreader

In short and in plain language

This post explains ARIA. ARIA is a tool for web pages. It tells aids like screen readers what a part of the page is.

Plain HTML is often better. A real button can do a lot. It also works with the keyboard. ARIA alone does not do that.

Some parts do not exist in HTML. Tabs or sliders are examples. There you need ARIA. The state must be right after each click. For example, if a menu is open.

Live regions report new content. The screen reader then reads it out. The region must be on the page before that.

Wrong ARIA can do more harm than good. We check whether your site gives screen readers the right information.

WAI-ARIA (Web Accessibility Initiative - Accessible Rich Internet Applications) is a powerful technique for making interactive components accessible to assistive technologies. At the same time, it is one of the most frequently misused techniques on the web. The ARIA Authoring Practices Guide puts this principle up front: no ARIA is better than bad ARIA (W3C WAI-ARIA Authoring Practices Guide, 2024). The WebAIM Million Report (2024) finds that homepages using ARIA have on average more detectable errors than those without; WebAIM stresses that ARIA does not necessarily cause these errors, as such pages tend to be more complex. This article shows how to use roles, states and live regions correctly, which WCAG requirements they relate to and how a professional audit uncovers broken ARIA.

Key takeaways

  • ARIA only describes, it never implements. A div with role=button is announced as a button yet is neither focusable nor operable with Enter or Space, while a native button element brings role, focus behaviour and keyboard handling with it.
  • The five W3C rules (Using ARIA, 2018): prefer a native element, do not override native semantics, make every interactive ARIA control keyboard operable, never put aria-hidden on focusable elements, and give every control an accessible name.
  • Tabs, tree views, comboboxes and two-handle sliders have no native HTML equivalent, so ARIA is required there. The ARIA Authoring Practices Guide (W3C, 2024) specifies the roles, states and keyboard interactions for each pattern.
  • States such as aria-expanded, aria-selected, aria-checked and aria-current must be updated by JavaScript on every interaction. Relationships via aria-controls or aria-labelledby point to IDs that must be unique and present in the DOM.
  • Live regions announce dynamic changes: polite is the default, assertive is reserved for urgent messages. The region must already exist in the DOM, even empty, otherwise nothing is announced.
  • The WebAIM Million Report (2024) found that pages using ARIA average more detectable errors than pages without it. A manual pass with at least two screen readers shows whether states are announced correctly and live regions fire on time.

What ARIA Is and What It Is Not

ARIA is a set of HTML attributes that provide assistive technologies with additional information about the role, state and properties of an element. This information feeds into the browser's accessibility tree, a representation of the page independent of visual presentation that screen readers read out. ARIA only changes how elements are described to assistive technologies. It adds no functionality: no focus behavior, no keyboard operation, no click handling.

This is exactly where a common misunderstanding lies. Writing a <div role="button"> produces an element that a screen reader announces as a button, but that is neither focusable nor responds to space or enter. The entire keyboard operation must be rebuilt in JavaScript. A native <button> brings all of that automatically. The ARIA Authoring Practices Guide states that, unlike HTML input elements, ARIA roles do not cause browsers to provide keyboard behaviors or styling (W3C WAI-ARIA Authoring Practices Guide).

ARIA falls into three categories: roles define what an element is, such as a tab, a dialog or a navigation region. States describe the current, changeable condition, such as whether an accordion is open or closed. Properties describe more static characteristics, such as a label or a relationship between elements. The boundary between state and property is fluid in practice, both are set via aria-* attributes.

The Five Core Rules of Using ARIA

The W3C defined five rules for using ARIA in its Using ARIA guide (W3C, Using ARIA, Working Draft 2018); the version discontinued in 2026 retains only the first four. They are the benchmark against which we measure the ARIA implementation in every WCAG audit. Internalizing these rules avoids many typical ARIA errors. The first rule alone resolves many problems at the root.

  1. Use a native HTML element with the desired semantics and behavior instead of repurposing a generic element with ARIA. A <button> is generally preferable to a <div role="button">.
  2. Do not change the native semantics of an element unless necessary. An <h2 role="tab"> hides from screen readers that this is a heading and is usually wrong.
  3. All interactive ARIA controls must be keyboard operable. An element with role="button" needs tabindex and keyboard handlers for enter and space.
  4. Do not hide focusable elements with aria-hidden="true". A focusable element hidden from screen readers creates a dead focus stop.
  5. All interactive elements need an accessible name, via visible text, aria-label or aria-labelledby.

No ARIA is better than bad ARIA

This rule of thumb from the ARIA Authoring Practices Guide (W3C, 2024) does not mean ARIA is bad, but that misused ARIA actively creates barriers. A missing attribute at worst makes an element less informative. A wrong attribute can make an element completely unusable, because the screen reader receives contradictory or misleading information.

Roles vs. Native HTML Semantics

Most ARIA roles have a native HTML equivalent that makes them unnecessary. The following comparison shows for typical use cases why the native variant is almost always the better choice. The underlying principle: native HTML brings role, focus behavior and keyboard operation in a single element that browsers and assistive technologies support out of the box.

Use caseNative HTMLARIA variant (avoid)
Button<button> - focusable, enter/space, role=button automatic<div role="button" tabindex="0"> - rebuild keyboard in JS
Link<a href> - role=link, focusable, in history<span role="link"> - no href, no keyboard operation
Navigation<nav> - creates landmark navigation automatically<div role="navigation"> - correct but unnecessary
Checkbox<input type="checkbox"> - state and operation native<div role="checkbox" aria-checked> - everything in JS
Heading<h2> - role=heading with aria-level=2<div role="heading" aria-level="2"> - error prone

However, there are components for which HTML offers no native equivalent. Tabs, a tree view, a slider with two handles, a tab panel system or a combobox pattern have no dedicated HTML element. Here ARIA is indispensable. The ARIA Authoring Practices Guide (W3C, 2024) documents the required roles, states and keyboard interactions for each of these patterns. Anyone building such a pattern should follow these specifications exactly rather than inventing their own concept.

tabs-pattern.html
<!-- Tabs: ARIA is correct here because HTML has no tab element -->
<div role="tablist" aria-label="Account settings">
  <button role="tab" id="tab-1" aria-selected="true"
          aria-controls="panel-1">Profile</button>
  <button role="tab" id="tab-2" aria-selected="false"
          aria-controls="panel-2" tabindex="-1">Security</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">...</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>...</div>

States and Properties: aria-expanded, aria-selected and More

States tell the screen reader the current changeable condition of a control. They are dynamic and updated via JavaScript whenever the component changes. Often the mistake is not a wrongly chosen attribute, but a state that is not updated after an interaction, so the screen reader reads out stale information.

aria-expanded

For collapsible elements like accordions, menus and disclosure buttons. Value true or false, must be updated on expand and collapse.

aria-selected

For selected options in tabs, listboxes and grids. Exactly one element per group carries true, the rest false.

aria-checked

For checkboxes, radios and switches in ARIA form. Values true, false or mixed (indeterminate tri-state).

aria-disabled

Marks an element as inactive without removing it from focus. Unlike native disabled, it stays focusable and readable.

aria-current

Marks the current element in a set, such as the active page in navigation (aria-current=page) or the current step.

aria-label / labelledby

Provide the accessible name. aria-labelledby references visible text by ID, aria-label sets an invisible name.

An accordion illustrates the principle. The triggering button gets aria-expanded, reflecting the open state, and aria-controls, pointing to the controlled panel. On every click, aria-expanded must toggle between true and false. If the implementation forgets this update, the screen reader permanently announces collapsed even though the content is visible. We check for and correct such missing state updates on existing components as part of accessible web development.

accordion.html
<!-- Accordion: aria-expanded MUST be updated on every click -->
<h3>
  <button aria-expanded="false" aria-controls="sect-1" id="btn-1">
    Shipping costs
  </button>
</h3>
<div id="sect-1" role="region" aria-labelledby="btn-1" hidden>
  <p>Within Germany we ship free from 50 euros.</p>
</div>

<script>
  // JavaScript toggles state AND hidden in sync
  const btn = document.getElementById('btn-1');
  btn.addEventListener('click', () => {
    const open = btn.getAttribute('aria-expanded') === 'true';
    btn.setAttribute('aria-expanded', String(!open));
    document.getElementById('sect-1').hidden = open;
  });
</script>

Wire up relationship attributes correctly

aria-controls, aria-labelledby and aria-describedby reference other elements by ID. These IDs must exist exactly and be unique. A common audit finding: the attribute references an ID that is not in the DOM (for example because an element is conditionally rendered) or that is assigned more than once. The screen reader then finds no reference or the wrong one.

Live Regions: Announcing Dynamic Content

Modern interfaces constantly update content without a full page reload: a filter reduces the result count, form validation shows an error, a cart counter changes, a toast notification appears. Sighted users notice these changes visually. Screen reader users only catch them if the change sits inside a live region. Live regions instruct the screen reader to automatically read out changes in a specific DOM area without focus having to move there.

aria-live="polite" is the default for nearly all updates. The screen reader waits until the current output finishes, then reads the change without interrupting the user. Suitable for status messages, updated result counts, success notices, save confirmations and search suggestions. aria-live="assertive" interrupts the ongoing output immediately and should be reserved exclusively for urgent messages, such as an error requiring immediate action or a session timeout. The WAI-ARIA specification explains why: an interruption may disorient users or keep them from completing their current task, so assertive should only be used when the interruption is imperative (W3C WAI-ARIA 1.2).

Instead of the attributes, you can also use the roles role="status" (equivalent to polite) and role="alert" (equivalent to assertive). They bring the matching live properties automatically and are often semantically clearer. For most status messages, role="status" is the simplest choice because it needs no additional attributes: according to the specification, the role has an implicit aria-live="polite" and aria-atomic="true" (W3C WAI-ARIA 1.2).

The live region must exist in the DOM beforehand

A common live region mistake: the container is created at the moment of the message and given aria-live at the same time. Then the change is not announced, because the screen reader was not yet observing the region when it came into being. The correct approach: insert the region once (even empty) into the DOM, and only then change its text content.
live-region.html
<!-- Region exists from the start, empty -->
<div id="status" role="status" aria-live="polite"></div>

<script>
  // Later only change the text content -> gets announced
  function announce(message) {
    document.getElementById('status').textContent = message;
  }
  // Example: announce('3 results for your filter selection');
</script>

<!-- WRONG: create region only on demand -> no announcement
  const div = document.createElement('div');
  div.setAttribute('aria-live', 'polite');
  div.textContent = 'Saved';
  document.body.appendChild(div); -->

Common ARIA Mistakes in Practice

The WebAIM Million Report (2024) shows a counterintuitive finding: pages that use ARIA have on average more detectable WCAG errors than pages without ARIA. WebAIM itself notes that ARIA does not necessarily cause these errors, as pages with ARIA tend to be more complex. Misused ARIA nevertheless remains a source of errors in its own right. The following error patterns are typical and can be identified and fixed systematically.

  • Redundant roles: <button role="button"> or <nav role="navigation"> repeat what the element already is. At best redundant, at worst confusing.
  • State not updated: aria-expanded stays at false even though the panel is open. The screen reader permanently reads out the wrong value.
  • aria-hidden on focusable elements: an element is reachable by keyboard but hidden from the screen reader. This creates a silent, confusing focus stop.
  • Orphaned relationships: aria-labelledby or aria-controls reference IDs that do not exist in the DOM or are assigned more than once.
  • Missing accessible name: an icon button without text and without aria-label is only announced as an unlabeled button.
  • Excessive assertive: marking every status message as assertive turns the page into a constant staccato of interruptions for screen reader users.

It is rarely in the user or author's best interest to try and use ARIA to override an interactive element, for instance a button, with a role generally exposed by a non-interactive element.

W3C WAI, ARIA in HTML

Testing ARIA with Screen Readers

Automated testing tools and browser developer tools detect a portion of ARIA errors, such as invalid attribute values, orphaned IDs or forbidden role combinations. But they cannot judge whether a state is correct in substance or whether a live region announces the right thing at the right time. The W3C states that tools cannot check all accessibility aspects automatically and that human judgement is required (W3C WAI, Selecting Web Accessibility Evaluation Tools). For ARIA, that means above all manual testing with real screen readers.

ARIA components should be tested with at least two screen readers, because their behavior differs. The screen readers available in Windows, macOS, iOS and Android together cover a large share of real usage. A tab system that works flawlessly in a Windows screen reader may require different keyboard operation in a macOS screen reader, and only direct testing reveals that.

A systematic ARIA test includes: traversing each component by keyboard, checking that every state is announced correctly, triggering every dynamic change and verifying the live region announcement, and reconciling against the keyboard patterns of the ARIA Authoring Practices Guide. Our WCAG audit operates every component by keyboard, checks in the screen reader output whether roles, names, states and live regions are correct after every change, and reconciles against the keyboard patterns of the ARIA Authoring Practices Guide; the announcement in a specific screen reader is not part of the audit.

Closely related to this topic are accessible forms, where ARIA attributes like aria-describedby, aria-invalid and aria-required play a central role in error communication. How these attributes interact with validation is described in detail in our article on accessible forms and validation.

This article is based on data from: W3C WAI-ARIA 1.2 Specification (2023), W3C ARIA Authoring Practices Guide (2024), W3C Using ARIA (Working Draft 2018), W3C ARIA in HTML (2024), W3C WAI Selecting Web Accessibility Evaluation Tools, WebAIM Million Report (2024).

Related Articles

WCAG & standards

Accessible AI Chatbots: WCAG-Compliant Voice Bots

When AI chatbots and voice assistants fall under the BFSG and how conversational UI becomes WCAG-compliant with ARIA live regions and focus management.

14 min read
WCAG & standards

Accessible Error and Status Messages with ARIA Live

Accessible error and status messages per WCAG 4.1.3 using ARIA live regions, role=alert, role=status and aria-describedby for forms and dynamic content.

13 min read
Practice & implementation

Screen Reader Optimization: Making Your Website Readable

Screen reader optimisation for websites: ARIA landmarks, roles, live regions, semantic HTML and screen reader testing on Windows, macOS and mobile devices.

14 min read