mixed-aria-state-attributes
Web validation
Some ARIA attributes describe what kind of control a button is, and how it behaves. Two of them are easy to mix up:
aria-pressedmakes a button a toggle button. It reports an on or off state of the button itself, like a Mute or Bold button.aria-expanded, often together witharia-controls, makes a button a disclosure button. It reports whether another part of the page, like a menu or a panel of filters, is shown or hidden.
A button can be one or the other, but not both. When a button has aria-pressed and also aria-expanded or aria-controls, assistive technology receives two state models for the same control. Screen readers may announce both states, or only one of them, depending on the screen reader and browser. Either way, users can't tell what the button does or what state it's in, which makes the interface hard to understand and operate.
To fix the issue, decide what the button does, and keep only the attributes for that purpose:
- If activating the button shows or hides another part of the page that users are meant to reach, it's a disclosure button. Remove
aria-pressed. - If activating the button changes a state without showing additional content, it's a toggle button. Remove
aria-expandedandaria-controls.
Pass Patterns
Disclosure button
The button shows and hides a panel, so it uses aria-expanded and aria-controls only.
<button aria-expanded="false" aria-controls="filters">Filters</button>
<div id="filters" hidden>
<!-- Filter options -->
</div>Toggle button
The button turns a setting on and off, so it uses aria-pressed only.
<button aria-pressed="false">Mute</button>Fail Patterns
Button with both aria-pressed and aria-expanded
The button shows and hides a panel, but it also reports a pressed state, so assistive technology gets two conflicting states.
<button aria-pressed="true" aria-expanded="true" aria-controls="filters">Filters</button>
<div id="filters">
<!-- Filter options -->
</div>Toggle button with aria-controls
The button only turns a setting on and off, but aria-controls gives it a disclosure relationship it doesn't have.
<button aria-pressed="false" aria-controls="player">Mute</button>WCAG techniques
Sufficient techniques
- ARIA5: Using WAI-ARIA state and property attributes to expose the state of a user interface component
- G108: Using markup features to expose the name and role, allow user-settable properties to be directly set, and provide notification of changes
Try It Yourself
Using a screen reader
New to screen reader testing, or need a refresher?
Review this article first: Practical guides for using screen readers
- Load the page and open a screen reader.
- Move to the button and listen to what the screen reader announces.
- Activate the button, and listen again.
Expected results: The screen reader announces one kind of state: either pressed or not pressed for a toggle button, or expanded or collapsed for a disclosure button.
Actual results: The screen reader announces both a pressed state and an expanded state, or the announced state doesn't match what the button does.
Inspecting the browser dev-tools
- In your browser's dev tools, select the button and open the Accessibility panel.
- Check the button's states and properties.
Expected results: The button has either a pressed state, or an expanded state with an optional aria-controls reference, but not both.
Actual results: The button has a pressed state together with an expanded state or an aria-controls reference.
FAQ
How does this issue relate to 4.1.2 Name, role, value?
SC 4.1.2 requires the states of user interface components to be programmatically determinable. When a button exposes both a pressed and an expanded state, its programmatic state no longer reliably describes the control, so assistive technology can't tell users what the button does or what happens when they activate it.
Why is this issue marked as Serious?
Screen reader users depend on the announced state to understand a button and decide whether to activate it. Conflicting states can make them misread the control or miss content it reveals, which makes the interface hard to understand and operate, so the issue is rated serious.
What if the button shows content and also looks pressed?
If activating the button shows or hides content, treat it as a disclosure button and use aria-expanded. The expanded state already tells users whether the content is shown, so aria-pressed adds nothing. A pressed visual style can stay; it doesn't need a matching aria-pressed attribute.
Standards and Regulations
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Personas impacted by this issue
Learn More
- WAI-ARIA Authoring Practices: Disclosure (Show/Hide) Pattern
- WAI-ARIA Authoring Practices: Button Pattern (including toggle buttons)
- WAI-ARIA 1.3: aria-pressed
- WAI-ARIA 1.3: aria-expanded
- Disclosure and Toggle Button UI patterns
- Relationships Between ARIA Roles and Attributes