Menu-based Select Widget Implementation Example with Expandable Groups
A link that doesn't go anywhere and a after the widget, as anchors to test tabbing through or out of the widget.
Testing Results and Commentary
Note on Windows High Contrast Mode (HC): To make selections more visually distinct when HC is
enabled, an underline
displays. We ensure icon visibility by setting forced-color-adjust: auto
in the SVG style attribute
and setting the property
fill='currentColor'
on the path.
Environment: Testing conducted June, 2022. All technologies evaluated at most recently released versions.
Summary: This select-like widget is based on a menu pattern, where the expandable items are menu
items and the
selectable items are at root level or within groups named by expandable menu items and are role of
menuitemcheckbox
. The
expandable menu items cannot be buttons with a role of menuitem
because VoiceOver Mac reports buttons
within this compound
widget as “interactive” and announces intstructions for interaction that break the widgets behavior.
Implementations must use
div
or span
as the element, in this widget in order to avoid this.
See the same general widget but with statically open (non-collapsable) groups.
Note: Only the first sub-group of menu items is using aria-describedby
to signal
group affiliation. The
other groups are related in code only by the fact that they appear inside of a role=group
. We are
doing this in order to
determine in testing if the aria-describedby
association is needed — the group container
should be enough to
signal affiliation within AT.
Note: If this widget were used along with a dynamic search, an appropriate aria-live
announcement of number
of results returned would be something like “X selectable items, in Y groups.” The calculation of this
should be easy, since
only the items with role of menuitemcheckbox
are selectable/checkable and determining group number
would be a simple DOM
query.
-
NVDA + Firefox: Trigger button announces as a named button that is collapsed and has a
“sub menu.”
Expanded and collapsed states announce as expected on menu items. Checkbox menu items announce both checked and
not-checked states. The
name of the groupings announce when navigated into or focused from the trigger button (so the
aria-describedby
associations are not strictly necessary). Cardinality is announced, but is calculated at the root level and at the grouping level separately. So if such a menu has any expandable groupings, it is probably best to have only menuitem buttons at the root level and checkbox items always within groups. - Narrator + Edge: Announces name of trigger button, that it is collapsed and “has popup,” along with the button contents. Again, in order to properly interact with the component, Narrator's scan mode must be off (via Narrator + Spacebar). Cardinality is reported, but calculated upon how many items are currently visible/accessible. So, rather than counting the groupings independently, the set size increases when new items are revealed/menu items are expanded. Grouping labels are announced when you move into one, but there is no announcement that it is a group, per se — only the name is announced when moved into. Narrator announces the full role value of the elements it encounters — either menu item or menu item checkbox. Checked or not-checked and collapsed or expanded states are announced.
-
JAWS + Chrome: Announces trigger button as “button menu.” Announces cardinality
based on the total number
of exposed menu items. Also announces position within that set. The expandable menu items are announced as
having a sub-menu, through
the inclusion of
aria-haspopup
. We only hear announcement of collapsed or expanded state of menu items after the state changes/the item is expanded/collapsed. There is no announcement of group affiliation, thus usingaria-describedby
associations may be a good idea. -
Android Talkback + Chrome: Talkback announces “checkbox” for the checkbox menu
items and checked or not
checked state is accurately reported. Buttons are announced as “menu item,” and collapsed/expanded
state is correctly
announced. Like iOS VoiceOver, there is no cardinality at any level and we only get a sense of group affiliation
via usage of
aria-describedby
. So, to provide the richest experience for mobile screen readers, it is probably best to use that technique. When a selection is made and the menu closes, the trigger button is focused and we hear “out of menu.” -
iOS VoiceOver + Safari: When on the trigger button, we hear all of its associated names and
descriptions, along with
“pop-up button, menu pop-up, double-tap to activate the picker.” So this announces similarly to a
native select control.
Menu items checkboxes are announces as checked or not checked. But, oddly, when a collapsed button menu item is
expanded, it is
announced as “selected.” As mentioned above, there is no annoucnement of cardinality and group
affiliation is only explicit
if
aria-describedby
is used. -
Mac VoiceOver + Safari: Announces “menu pop-up button, ... to display a list of options,
press control-option
space.” The instruction “to close, press escape” is also a proper instruction. When items are
marked checked and
refocused, they announce “1, [the name of the item], checked.” It is unclear why the number 1 is
prepended to the
announcement, but the behavior is consistent (if confusing). Expandable menu items are reported as collapsed or
expanded, as expected.
When the menu is first entered, the screen reader reports the total number of items. Cardinality beyond that can
get confusing, as
sometimes expanded groups are included in the number count. Using
aria-describedby
to help with group affiliation may be warranted, since there is no consistent reporting of group names/affilation. VoiceOver also interprets the CSS all-capped DOGS as an acroymn, for some reason, and spells it out. This is appears to be a VoiceOver bug.