ARIA States and Properties
Beyond role, ARIA defines a set of attributes that describe an element's accessible name, relationships, and current state. These fall into two categories: properties, which are mostly static, and states, which change as the user interacts with the page.
Properties vs states
Category | Behavior | Examples |
|---|---|---|
Properties | Describe essential characteristics, rarely change once set | aria-label, aria-labelledby, aria-describedby |
States | Describe current conditions, expected to change dynamically | aria-expanded, aria-hidden, aria-checked, aria-disabled |
aria-label and aria-labelledby
Both provide an accessible name for an element that either has no visible text, or whose visible text isn't descriptive enough on its own.
<!-- aria-label: an inline string, when there's no visible text to reference --> <button aria-label="Close dialog">×</button> <!-- aria-labelledby: points to the id of another element that IS the label --> <h2 id="billing-heading">Billing Address</h2> <section aria-labelledby="billing-heading">...</section>
aria-label overrides any visible text content — use it only when there truly is no visible label.
aria-labelledby references one or more existing element ids, and is preferred when a visible label already exists.
aria-labelledby can combine multiple ids (space-separated) to build a compound label.
aria-describedby
Points to an element containing supplementary description — read after the accessible name, useful for hints, help text, or error messages.
<label for="pwd">Password</label> <input id="pwd" type="password" aria-describedby="pwd-hint" /> <p id="pwd-hint">Must be at least 8 characters.</p>
aria-hidden
<!-- Decorative icon, redundant with visible adjacent text --> <button> <span aria-hidden="true">🗑️</span> Delete </button>
aria-hidden="true" removes an element (and its descendants) from the accessibility tree entirely — assistive technology skips it completely, even though it's still visible on screen. Use it for purely decorative icons, or duplicated content that would otherwise be announced twice.
aria-expanded
<button aria-expanded="false" aria-controls="menu">Options</button> <ul id="menu" hidden>...</ul>
Announces whether a collapsible control (a menu button, an accordion header, a disclosure triangle) is currently open or closed. Toggle it in JavaScript alongside the actual show/hide logic.
aria-live regions
<div aria-live="polite" id="status"></div> <div aria-live="assertive" role="alert" id="error"></div>
Value | Behavior |
|---|---|
polite | Announced when the screen reader is next idle — for non-urgent updates like "Saved" or a filtered result count |
assertive | Announced immediately, interrupting whatever the screen reader is currently saying — for urgent errors |
off | The default — changes to this region are not announced |
aria-live regions must exist in the DOM before content changes inside them — inserting the whole element and its new text at once is often missed by screen readers, which need to already be "watching" the region.
aria-expanded="false" on a menu that is actually open is worse than no attribute at all, since it actively misinforms assistive technology users.