Check-All / Expand-All Controls
Controls that can operate other controls in bulk are not new. One common example is a single checkbox that allows you to check or uncheck a group of checkboxes. Another example is a single button that lets you expand or collapse a set of disclosure widgets. When the user operates one from the set, the bulk control then reflects that.
For example, you may choose “All toppings” for your ice cream sundae, which checks every checkbox for every topping. Then you uncheck “Butterscotch” because you want to exclude that terrible sauce. The “All toppings” checkbox should visually and programmatically change to reflect that not all toppings are checked.
You can visit the demo directly. Bear in mind it is not production-ready code.
WCAG
WCAG Success Criterion 4.1.2 Name, Role, Value requires that the state of the bulk operation control is conveyed programmatically.
That “check all” or “expand all” control has to support situations where not everything it controls is currently in the same state as the others. This means a simple on/off won’t do; you need a control that supports three states — a tristate control.
HTML
Only one HTML control supports tristate, and that is the checkbox. While the WHATWG HTML specification says it is not a tristate control, authors can use script to set a checkbox to “indeterminate”, which is exposed to users through platform accessibility APIs as “mixed”.
Authors could use aria-checked="mixed"
, but don’t do this unless you are making a custom ARIA checkbox
or menuitemcheckbox
(ugh). For HTML checkboxes the HTML programmatic state overrides the ARIA programmatic state, so it’s best not to use it. See § 3.5.18 and § 3.5.19 of HTML Accessibility API Mappings 1.0 for more detail than I am interested in giving in this sub-500 word post.
ARIA
Only one non-HTML ARIA control supports tristate, specifically via aria-pressed
through the mixed
value. Be aware that the aria-pressed
attribute is only allowed on a <button>
(or button
role, but ugh).
A switch control is not an option since it allows only two states — the ARIA switch
role disallows a mixed state. The proposal to make a native HTML switch control also disallows a mixed state. You can read more in my post Switch Role Support.
Recap
To recap, here are your options:
- Use
<input type="checkbox" [checked]>
if you want to bulk check / uncheck a bunch of checkboxes. - Use
<button aria-pressed="true|false|mixed">
if you want to bulk expand / collapse a bunch of disclosures. - You can use an ARIA checkbox or ARIA button for each instead, but probably don’t.
- If you have a scenario besides checkboxes or disclosures, then choose the most appropriate control.
This advice is not absolute, of course.
4 Comments
We’ve struggled a bit with similar expand/collapse controls in the component library I’ve been involved with. Originally we had an expand/collapse HTML button where the button text is always “Expand all” if there is at least one collapsed section, and “Close all” if all sections are open. The button had an aria-expanded=”true/false” attribute which was removed on my recommendation, since it wasn’t really appropriate in the first place and also didn’t reflect the mixed state accurately. Also changing both text and state can be confusing, even though I have it done even in some W3C examples.
Your suggestion of using a button with aria-pressed is interesting, but my issue with it is that on its own it does not communicate what will happen when the user presses the button in the “mixed” state. Do the sections collapse or expand? Because of this we now have only a button where we change the text and nothing else: this seems to most accurately convey what the button does in every situation. I know some screen readers will not immediately communicate the change in the accessible name without refocusing, but this seems less of a nuisance than having potentially confusing or conflicting state and accessible name. I would appreciate your thoughts on this!
In response to .[…] my issue with it is that on its own it does not communicate what will happen when the user presses the button in the “mixed” state. Do the sections collapse or expand?
Broadly speaking, my experience is that users are accustomed to checking the first item past the “do all” control since that first item acts as a proxy for the entire set. That being said, you can choose to always do one or the other and then include that in instructions.
I know some screen readers will not immediately communicate the change in the accessible name without refocusing, but this seems less of a nuisance than having potentially confusing or conflicting state and accessible name.
In the end, those are effectively the same thing — requiring the user to explore subsequent related controls. An accessible name that lies about the state is little different for users than a state and name that is ambiguous. Arguably, the first sows distrust while the second is at least honest about its ambiguity. Unless you address it as I noted just above, of course.
In response to .Thank you for the reply and insight! As I see it, changing the visible label (as we are doing now) allows for a more explicit indication of what will happen, i.e. “Expand all” or “Collapse all”. What I gather from this, is that for screen reader use, the lack of a state on the button is not an issue because the label already says what will happen, and users can verify this by moving to the first item in the set. Aria-pressed would only work well with a constant label.
In response to .As I see it, changing the visible label (as we are doing now) allows for a more explicit indication of what will happen, i.e. “Expand all” or “Collapse all”.
Provided the user knows the language of the page and does not auto-translate it into something that may be… weird. Though if (when) the visible label (which I hope is also the accName) falls out of sync with the current state you will have problem of lying to users. Which I note in my previous reply.
What I gather from this, is that for screen reader use, the lack of a state on the button is not an issue because the label already says what will happen, and users can verify this by moving to the first item in the set.
We disagree there. The lack of state means the author has to have to have conveyed the meaning and intent properly (in addition to intended state). My experience is that is not always (nor often enough) the case.
Aria-pressed would only work well with a constant label.
You have that inverted.
aria-pressed
works well unless you have an inaccurate label.Either way, all that matters is whatever solution you use works for your users. So speculate as much as necessary to inform a prototype, then build it, then get it in front of your users, then decide based on those outcomes.
Leave a Comment or Response