Skip to main content
Accessibility

Role, State, and Property

  • ARIA
  • roles
  • states
  • properties
  • assistive technology

WAI-ARIA (Web Accessibility Initiative – Accessible Rich Internet Applications) provides a vocabulary of roles, states, and properties that authors can add to HTML elements to bridge the gap between custom widgets and the accessibility information that assistive technologies need. Together, these three categories form the backbone of how the browser’s accessibility tree describes every interactive or informational element on the page.

A role tells assistive technologies what an element is (e.g., a button, a tab, a navigation landmark). A state communicates the element’s current condition — something that typically changes during user interaction (e.g., aria-expanded="true", aria-checked="false"). A property describes a more persistent characteristic of the element that is less likely to change frequently (e.g., aria-label, aria-describedby, aria-required). While the line between states and properties can be subtle, understanding the distinction helps authors build interfaces that keep assistive technologies informed as users interact with the page.

Why Role, State, and Property matters

When native HTML semantics are insufficient — for instance, when building a custom combobox, tree view, or drag-and-drop interface — ARIA roles, states, and properties fill in the missing accessibility information. Without them:

  • Screen reader users cannot tell what a custom widget is or how to operate it, because the accessibility tree contains only generic elements like <div> or <span>.
  • Voice-control users may be unable to target or activate controls that lack recognizable roles.
  • Automated validators flag missing or incorrect ARIA usage, signaling that the content may be inaccessible.
  • Keyboard-only users lose orientation cues such as expanded/collapsed states and current-item indicators.

Correct use of roles, states, and properties ensures that the dynamic behaviour visible on screen is also conveyed programmatically, fulfilling WCAG success criteria like 4.1.2 Name, Role, Value and 1.3.1 Info and Relationships.

How Role, State, and Property works

Roles

A role attribute overrides an element’s implicit semantics. Roles fall into several groups:

  • Landmark rolesbanner, navigation, main, contentinfo, etc. — define page regions.
  • Widget rolesbutton, tab, slider, dialog, menu, etc. — describe interactive controls.
  • Document-structure rolesheading, list, img, table, etc. — mirror structural HTML elements.
  • Live-region rolesalert, log, status, timer — tell assistive technologies to announce dynamic content updates.

It is best practice to rely on semantic HTML first (<button>, <nav>, <main>) and only add explicit roles when native elements cannot provide the required semantics.

States

States reflect conditions that change as users interact with the interface. Common states include:

  • aria-expanded — indicates whether a collapsible section is open or closed.
  • aria-selected — marks the currently selected item in a list or set of tabs.
  • aria-checked — mirrors the checked/unchecked/mixed condition of checkboxes.
  • aria-disabled — signals that an element is visible but not operable.
  • aria-hidden — removes an element from the accessibility tree entirely.

Authors must keep state attributes in sync with the visual presentation by updating them via JavaScript whenever the UI changes.

Properties

Properties tend to be set once (or change rarely) and describe structural relationships or labels:

  • aria-label and aria-labelledby — provide an accessible name.
  • aria-describedby — links an element to supplementary descriptive text.
  • aria-required — indicates a required form field.
  • aria-controls — identifies which element is controlled by the current one.
  • aria-live — sets the politeness level for a live region (polite, assertive, off).

Interaction between all three

A single element often combines a role with several states and properties. The browser compiles this information into the accessibility tree, which assistive technologies query to present content to the user.

Code examples

Bad example — custom disclosure button with no ARIA

In this example, a <div> is styled to look like an expandable button, but assistive technologies see only a generic container with no role, no state, and no accessible name.

<div class="toggle" onclick="togglePanel()">
  Show details
</div>
<div class="panel" id="details" style="display:none;">
  <p>Here are the extra details.</p>
</div>

A screen reader will announce this as plain text with no indication that it is interactive or that it controls a collapsible panel.

Good example — custom disclosure button with roles, states, and properties

<button
  type="button"
  aria-expanded="false"
  aria-controls="details"
  onclick="togglePanel(this)">
  Show details
</button>
<div class="panel" id="details" hidden>
  <p>Here are the extra details.</p>
</div>

<script>
  function togglePanel(btn) {
    const panel = document.getElementById("details");
    const isExpanded = btn.getAttribute("aria-expanded") === "true";
    btn.setAttribute("aria-expanded", String(!isExpanded));
    panel.hidden = isExpanded;
  }
</script>

Here the native <button> element already carries the implicit role of button. The state aria-expanded tells screen readers whether the panel is open or closed and is toggled via JavaScript. The property aria-controls communicates which element the button operates. This gives assistive technology users the complete picture: what the element is, what it controls, and what condition it is in.

Bad example — incorrect role and missing state on tabs

<ul>
  <li class="active" onclick="showTab(0)">Tab 1</li>
  <li onclick="showTab(1)">Tab 2</li>
</ul>

Good example — proper tab pattern with roles, states, and properties

<div role="tablist" aria-label="Settings">
  <button role="tab" id="tab-1" aria-selected="true" aria-controls="panel-1">
    General
  </button>
  <button role="tab" id="tab-2" aria-selected="false" aria-controls="panel-2" tabindex="-1">
    Privacy
  </button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
  <p>General settings content.</p>
</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
  <p>Privacy settings content.</p>
</div>

In this pattern the roles (tablist, tab, tabpanel) describe the widget structure, the state aria-selected marks the active tab, and the properties aria-controls and aria-labelledby establish relationships between tabs and their panels. Together they form a fully accessible tab interface that any screen reader can navigate and announce correctly.

Help us improve this glossary term

Was this guide helpful?

Scan your site

Rocket Validator scans thousands of pages in seconds, detecting accessibility and HTML issues across your entire site.

🌍 Trusted by teams worldwide

Validate at scale.
Ship accessible websites, faster.

Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.

Scheduled Reports
API Access
Open Source Standards
$7 / 7 days

Pro Trial

Full Pro access. Cancel anytime.

Start Pro Trial →

Join teams across 40+ countries