Day 16: Icon buttons should be labelled with aria-label
Tags: a11y, html, button, svg
Published: 2021-12-17 07:35:32

## 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:

![An iPhone screen showing four icon buttons over a full-screen street map](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w3ow89ok7ecmf8sdckh3.png)

**My Ideal Map App's main screen** (screenshot by the author)

When clicked:

1. the top-left button with a hamburger menu icon will show a menu; 
2. the top-right button with a magnifier icon will show a search box; 
3. the bottom-right button with a flight-takeoff icon will show the user's current location on the street map; and 
4. 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**](https://dev.to/masakudamatsu/day-7-making-buttons-look-like-clouds-for-embedded-google-maps-33po).)

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](https://www.tpgi.com/what-is-an-accessible-name/) 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 

1. “Show menu”
2. “Search place”
3. “Track your location”
4. “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:

```html
<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)](https://www.smashingmagazine.com/2021/03/good-better-best-untangling-complex-world-accessible-patterns/#accessible-svg-patterns). See also [Migliorisi (2016)](https://css-tricks.com/accessible-svgs/#2-inline-svg).

However, using this method as a button label turns out to be not a good idea. [O'Hara (2019)](https://www.scottohara.me/blog/2019/05/22/contextual-images-svgs-and-a11y.html) 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](https://2567b1ff.mima.pages.dev/). Using Chrome DevTools' accessibility panel, you can see:

1. 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): ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sqq2edisa8inp7ffsddy.png)

2. The top-right button **has no accessible name**, even though its SVG icon does have an accessible name of "Search place": ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jjmhnyblqr5duplgn2x.png)

3. 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: ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/znyhp2jnyq1ao4lbdb72.png)

4. 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":      ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ga0n81fya1tgrndyzm02.png)

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](https://testing-library.com/docs/cypress-testing-library/intro/). While I was writing some tests for [Cypress](https://cypress.io/) to test-drive the search feature of the app, I wrote this line of code:

```js
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](https://testing-library.com/docs/cypress-testing-library/intro/) 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`.

```html
<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](https://www.tpgi.com/what-is-an-accessible-name/) 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)](https://www.sarasoueidan.com/blog/accessible-icon-buttons/) and [O'Hara (2019)](https://www.scottohara.me/blog/2019/05/22/contextual-images-svgs-and-a11y.html) 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](https://5df230c6.mima.pages.dev/). Now all the buttons have accessible names:

1. The top-left button with a hamburger menu icon shows an accessible name of "Show menu": ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u14nge7sdap3wyt2q0uk.png)

2. The top-right button with a magnifier icon shows an accessible name of "Search place": ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1dc051vbnx4mdri9dko.png)

3. The bottom-right button with the airplane icon shows an accessible name of "Track your location": ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b5840dux6msxe3vx2p2v.png)

4. The bottom-right button with the plus sign icon shows an accessible name of "Save place": ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rly1y4kjfxaz9zbcpkeg.png)

### Other approaches

[Soueidan (2019)](https://www.sarasoueidan.com/blog/accessible-icon-buttons/) 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](https://www.smashingmagazine.com/2021/03/good-better-best-untangling-complex-world-accessible-patterns/)”, *Smashing Magazine*, Mar 16, 2021.

Migliorisi, Heather (2016) “[Accessible SVGs](ttps://css-tricks.com/accessible-svgs)”, *CSS-Tricks*, Jul 6, 2016.

O'Hara, Scott (2019) “[Contextually Marking up accessible images and SVGs](https://www.scottohara.me/blog/2019/05/22/contextual-images-svgs-and-a11y.html)”, _scottohara.me_, May 22, 2019.

Soueidan, Sara (2019) “[Accessible Icon Buttons](https://www.sarasoueidan.com/blog/accessible-icon-buttons/)”, _sarasoueidan.com_, May 22, 2019.

Watson, Léonie (2017) "[What is an accessible name?](https://www.tpgi.com/what-is-an-accessible-name/)", _TPGi_, Apr 11, 2017.