TL;DR
Use aria-label
to give accessible names to icon buttons. Browsers may fail to recognize an icon image's own accessible name as its parent <button>
element's accessible name.
Introduction
My Ideal Map App, a web app I'm building, has four icon buttons on its main screen:
My Ideal Map App's main screen (screenshot by the author)
When clicked:
- the top-left button with a hamburger menu icon will show a menu;
- the top-right button with a magnifier icon will show a search box;
- the bottom-right button with a flight-takeoff icon will show the user's current location on the street map; and
- the bottom right button with a plus sign icon will show a dialog to save a place on the map.
(For more detail on these buttons, in particular on why they take an unusual button shape, see Day 7 of this blog series.)
To make these buttons accessible for screen reader users, I need to assign an accessible name to each button.
An accessible name is what screen readers will announce to the visually impaired user (see Watson 2017 for more detail). If a button has text as its label, its accessible name is the label text. If a button has only an icon image, we need to figure out how to give it an accessible name. Otherwise, screen readers will just announce "button", leaving the user unsure of what will happen after they press the button.
So I want to give accessible names to these four buttons as
- “Show menu”
- “Search place”
- “Track your location”
- “Save place”
This way, screen reader users will be able to tell what will happen after they press these buttons.
Today I've learned something about how to implement this with HTML. So I'd like to share it with you below.
Initial attempt
Initially, I defined an accessible name to the icon image (an <svg>
element), hoping that it would be equivalent of the button's label text. Taking the top-left menu button as an example, here's the HTML code I initially wrote:
<button type="button">
<svg viewBox="0 0 56 48"
width="56px"
height="48px"
role="img"
aria-labelledby="menu">
<title id="menu">
Show menu
</title>
<--! SVG image code to be inserted -->
</svg>
</button>
Adding role="img"
to the <svg>
element will indicate that the SVG image is not decorative (so screen readers won't skip it). To give an "alt text" to the inline SVG image, I added a <title>
element as the <svg>
element's child and referred to its id
attribute value with aria-labelledby
in the <svg>
tag. This is the best practice to make an inline SVG image accessible, according to Fisher (2021). See also Migliorisi (2016).
However, using this method as a button label turns out to be not a good idea. O'Hara (2019) notes that some combinations of browsers and screen readers won't recognize the <svg>
element's accessible name as its parent <button>
element's accessible name.
I myself experienced the same issue with Chrome (version 96.0.4664.110). Two of the four buttons don't have accessible names, even though I used exactly the same HTML code structure for all the four buttons...
Here's a demo. Using Chrome DevTools' accessibility panel, you can see:
The top-left button shows an accessible name of "Show menu", which is the same as its SVG icon's (defined in the
<title>
element):The top-right button has no accessible name, even though its SVG icon does have an accessible name of "Search place":
The bottom-right button with the airplane icon shows an accessible name of "Track your location", which is the same as its SVG icon's:
The bottom-right button with the plus sign icon has no accessible name, even though its SVG icon has an accessible name of "Save place":
This is so weird... Seems like browsers do not consistently recognize an accessible name of the icon image as a button's label text.
Digression: How I've noticed this bug
Incidentally, I noticed the bug thanks to Cypress Testing Library. While I was writing some tests for Cypress to test-drive the search feature of the app, I wrote this line of code:
cy.findByRole('button', {name: 'Search place'}).click();
This simulates the user's action of clicking the button whose accessible name is 'Search place'. However, I got an error while running this test, because there was no button with its accessible name being 'Search place'.
What's great about Cypress Testing Library is that accessibility tests are effectively build-in. It forces us to simulate the user's action as if the user were using screen readers.
Solution: Using aria-label
instead
Rather than figuring out how to solve this bug, I go with an alternative approach to give an accessible name to an icon button: the use of aria-label
.
<button
aria-label="Show menu"
type="button"
>
<svg
aria-hidden="true"
viewBox="0 0 56 48"
width="56px"
height="48px"
>
<--! SVG image data to be inserted -->
</svg>
</button>
The aria-label
attribute gives an accessible name (see Watson 2017 for more detail). It is usually not recommended because the sighted users won't be able to read it. For icon buttons, however, the sighted users can tell what the button is for, by seeing the button's icon. So the use of aria-label
is justified. This is an approach recommended by Soueidan (2019) and O'Hara (2019) for labelling icon buttons.
Now the inline SVG image is no longer meaningful for screen readers. So the role="img"
attribute and the <title>
element are both removed, and the aria-hidden="true"
is added to hide the <svg>
element from screen readers.
Here's the demo after the fix. Now all the buttons have accessible names:
The top-left button with a hamburger menu icon shows an accessible name of "Show menu":
The top-right button with a magnifier icon shows an accessible name of "Search place":
The bottom-right button with the airplane icon shows an accessible name of "Track your location":
The bottom-right button with the plus sign icon shows an accessible name of "Save place":
Other approaches
Soueidan (2019) suggests two other approaches to give accessible names to icon buttons: using text "visible" only to screen readers (while hiding SVG to them) or using aria-labelledby
to refer to a hidden <span>
element that contains text. But the use of aria-label
is much more straightforward to implement.
Today's lesson
I've learned something today. For icon buttons, use aria-label
to define its accessible name. Don't rely on the icon SVG image's accessible name.
References
Fisher, Carie (2021) “Good, Better, Best: Untangling The Complex World Of Accessible Patterns”, Smashing Magazine, Mar 16, 2021.
Migliorisi, Heather (2016) “Accessible SVGs”, CSS-Tricks, Jul 6, 2016.
O'Hara, Scott (2019) “Contextually Marking up accessible images and SVGs”, scottohara.me, May 22, 2019.
Soueidan, Sara (2019) “Accessible Icon Buttons”, sarasoueidan.com, May 22, 2019.
Watson, Léonie (2017) "What is an accessible name?", TPGi, Apr 11, 2017.
Top comments (0)