Description
Description
ActionMenu
has preferred API of ActionMenu.Button
which uses a Primer Button
and wires it up correctly.
However, if you want to customise the anchor, we also provide a ActionMenu.Anchor
that can be used to give a custom element.
While this API is required, it's possible to use it incorrectly.
Spotted in the wild: In this example, the developer is trying to add an "active indicator" on the IconButton by adding an additional element (with aria-label) and positioning it
<ActionMenu.Anchor>
<div className="relative">
<IconButton aria-label="Filter files in tree" icon={FilterIcon} />
{filterEnabled && (
<div aria-label="Showing only files changed" className="active-indicator" />
)}
</div>
</ActionMenu.Anchor>
The above JSX renders inaccessible html:
<div
class="relative"
id=":rku:" <!-- used to label the menu when open, this should have been on the button? -->
aria-haspopup="true"
aria-expanded="false"
tabindex="0" <!-- tabindex=0 added by ActionMenu to make sure anchor gets focus -->
>
<button
data-component="IconButton"
type="button"
aria-labelledby=":rl0:" <!-- points to tooltip -->
aria-describedby=":rl1:-loading-announcement"
>
<svg aria-hidden="true"></svg>
</button>
<span
class="Tooltip__StyledTooltip-sc-e45c7z-0 iBBTma"
id=":rl0:"
aria-hidden="true"
popover="auto"
>
Filter files in tree
</span>
<div aria-label="Showing only changed files" class="absolute active-indicator"/>
</div>
iconbutton-grouped.mov
Video description:
- Pressing tab on the close button seems to focus the filter button but does not show tooltip.
- The screen reader reads out "Filter files in tree, Showing only changed files, menu pop-up, group"
- You'd expect tabbing again would focus the text input, but it focuses the button instead. Now a tooltip is visible with text "Filter files in tree".
- The screen reader now reads "Filter files in tree, button, Filter files in tree, Showing only changed files, menu pop-up, group" (still reading out the group)
- Tabbing again finally focuses the text input
Proposed Solution
I have 2 suggestions:
- Reduce: The most common use case of
ActionMenu.Anchor
is to use anIconButton
, we should create a shortcutActionMenu.IconButton
as a companion toActionMenu.Button
.
A blessed shortcut would reduce the chances of implementing it incorrectly. - Validate:
ActionMenu.Anchor
should validate it's children, if it receives an incorrect element as the root, it should throw a warning and guide the developer to correct usage.
My guess is that only button is valid, but we need to validate that assumption. Non-interactive element is definitely a violation. For prior art, we have similar (if not more advanced) checks in Tooltip
Suggested prioritisation:
I have fixed the instance where this was spotted so I am not blocked.
But there are 258 instances of ActionMenu.Anchor
that need to be audited for their children to decide if this is a widespread bug or a good to have
Steps to reproduce
Navigate to custom anchor story and replace the Anchor with:
<ActionMenu.Anchor>
<div className="relative">
<IconButton aria-label="Filter files in tree" icon={FilterIcon} />
{filterEnabled && (
<div aria-label="Showing only files changed" className="active-indicator" />
)}
</div>
</ActionMenu.Anchor>
Version
v37.5.0
Browser
Chrome