aria-expanded
Indicates 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.
When to use
On any control that opens and closes another region of the UI: an accordion header, a “show more” disclosure button, a combobox trigger, a menu button, a treeitem with children, a hamburger nav toggle. The control stays the same element across both states — only the attribute flips.
If the control toggles state on the element itself (mute / unmute, follow / unfollow), use aria-pressed instead. aria-expanded describes a relationship with another region, usually identified by aria-controls.
The role determines whether aria-expanded is meaningful: it is supported on button, combobox, link, tab, treeitem, menuitem, gridcell, row, and a few others. Putting it on a <div> with no role does nothing useful.
How to keep it in sync
Valid values are "true" (region is open) and "false" (region is closed). The default if omitted is “no expanded state at all” — which is different from "false". If your control is ever expandable, render aria-expanded="false" in the closed state rather than leaving it off.
Update the attribute in the same code path that animates the region open or closed. The attribute is the source of truth that screen readers read; the visual chevron is a secondary cue for sighted users.
Pair with aria-controls="<region-id>" so the screen reader can announce the relationship: “Filters, button, collapsed, controls filter-panel”. Some assistive technologies offer a shortcut to jump to the controlled region.
Common failures
- Toggling a CSS class on the panel but forgetting to flip
aria-expanded. - Using
aria-expandedon a non-interactive element with no role. The attribute is ignored. - Adding
aria-expanded="true"only — never rendering the"false"state. Screen readers announce nothing in the closed state. - Using
aria-expandedon a control that doesn’t actually expand a region (a “Submit” button). - Confusing
aria-expandedwitharia-pressedon toggle buttons that don’t open a separate region. - Omitting
aria-controls, leaving the relationship between trigger and panel implicit.
Example
<button
type="button"
aria-expanded="false"
aria-controls="filters-panel"
onclick="toggle(this)"
>
Filters
</button>
<div id="filters-panel" hidden>
<!-- filter controls -->
</div>