Accessible `IconButton` with label viewable as `Tooltip`
See original GitHub issueSummary
There is no documented example of how to render an icon-only button with an accessible tooltip in a way that would meet all of the following standard requirements:
- Render as an icon-only button with a single focus target
- Read the label one time in a manner that ties it to the button, for screen reader users
- Show the label on hover, for mouse users
- Show the label on focus, for keyboard users
If this is a supported behavior, then some documentation is needed to show how to do it. If this is not supported, it would be very useful functionality to add to Primer.
The IconButton
documentation provides an example of how to label the component in an accessible manner:
<IconButton aria-label="Search" icon={SearchIcon} />
And the Tooltip
documentation has the same:
<Tooltip aria-label="Hello, Tooltip!">Text with a tooltip</Tooltip>
Both of these examples use aria-label
however, which provides no obvious way to create an icon button that shows its accessible label on hover as a tooltip.
Use Cases
This is a very common requirement. See for example these instances on github.com:
Notifications bell:
Markdown editor toolbar:
Code view:
This is recommended as a best practice by Primer’s own tooltip guide:
Attempts
I’ve tried all of the following examples but I haven’t been able to find a satisfying way to do this:
Label on tooltip: Tooltip does not appear on button focus and the button appears as unlabelled in the accessibility tree.
<Tooltip aria-label="Bold">
<IconButton icon={BoldIcon} />
</Tooltip>
Label on button only: Tooltip does not work at all.
<Tooltip>
<IconButton icon={BoldIcon} aria-label="Bold" />
</Tooltip>
Label on both: The label will be read twice to screen readers (something like “Tooltip: Bold, Button: Bold”) which is unnecessarily redundant. Also the tooltip still doesn’t appear on focus.
<Tooltip aria-label="Bold">
<IconButton icon={BoldIcon} aria-label="Bold" />
</Tooltip>
Tooltip as button: Seems like a promising idea but Tooltip
does not support the as
prop.
<Tooltip aria-label="Bold" as={IconButton} icon={BoldIcon} />
Button as tooltip: Renders an unfocuseable span
instead of a button
.
<IconButton icon={BoldIcon} as={Tooltip} aria-label="Bold" />
Tooltip in button children: Does not work because the IconButton
ignores children.
<IconButton icon={BoldIcon} aria-label="Bold">
<Tooltip aria-label="Bold" role="presentation">Bold</Tooltip>
</IconButton>
Tooltip as button icon: This is horribly inelegant, but it does generate a good accessibility tree and still shows the tooltip on hover. It unfortunately still doesn’t show the tooltip on focus, but it’s the best I have for now.
<IconButton
icon={() => <Tooltip aria-label="Bold" role="presentation"><BoldIcon /></Tooltip>}
aria-label="Bold"
/>
Proposed Solution
My ideal solution would be to just show the IconButton
’s aria-label
as a tooltip by default.
To configure this, I propose adding two new props to the IconButton
component:
disableTooltip
: Turn off the tooltip.tooltipProps
: Configure the tooltip by passing props to the underlyingTooltip
component.
Then I could achieve my goal simply with:
<IconButton icon={BoldIcon} aria-label="Bold" />
Issue Analytics
- State:
- Created a year ago
- Comments:24 (20 by maintainers)
Top GitHub Comments
Hi @lesliecdubs!
@hectahertz can speak more to the work on
IconButton
in PVC! I believe we were leaning towards having tooltip by default for allIconButton
for accessibility purposes. Discussion can be found in: https://github.com/primer/view_components/pull/1062.As a side note, I notice in all the examples listed in this issue, the tooltip is always semantically associated as a label. I’m not sure if this is out of scope, but in the long run, the tooltip should also be allowed to be associated to the icon button as a supplementary description.
You can check out the markup of the markdown toolbar in dotcom as an example. These were recently updated to use tooltips that are associated semantically using
aria-describedby
witharia-label
directly set on the button with a brief accessible name. This was done (at least in dotcom) because the tooltip content is kind of long and contains keyboard shortcuts which makes the tooltip inappropriate as an accessible name. Accessible names should be brief. Therefore you’ll notice we have a label likeBold
directly on the button and a tooltip associated as description that contains,Add bold text, <Cmd+b>
.We don’t have this in dotcom, but similarly in the
Notifications
button example, it may be appropriate to setaria-label
asNotifications
, and set a tooltip as supplementary description withYou have unread notifications
.We’ve recently worked on a bunch of accessibility doc improvements on the PVC and Primer Design side to encourage proper tooltip usage with valid tooltip use examples. Here are some references that may be helpful as Primer React team works on tooltip:
hideTooltip:
Yep, I agree with you.
tooltip=false
only made sense while there was atooltip="some text"
prop on theIconButton
.We should disable it automatically. Both context and children magic would work here.
Yes! 💯
This should be a super rare use case. We could even start by not adding it to the public API at all and only using it internally, for example in TreeGrid.
Automatic tooltip:
Vote recorded!
You’re right, ideally tooltip content should be a description instead of simple label. But, I fear folks would often not use one 😢
Personal opinion: anything we can do by default, without getting in the way of them doing better is a step in the right direction.
longer personal opinion from above:
Rich text Tooltips:
I agree with both of you. But, I think we should exclude shortcuts and other rich text for this conversation and come back to it after along with other components that use shortcuts. There is a broader pattern there.
Summary
Leaning towards these decisions:
IconButton
APIaria-label
compulsory onIconButton
hideTooltip
to public API just yet.