Here’s how I’d handle various common SVG icon scenarios with accessibility in mind.
Just an icon
So this is an icon that’s not within a link or button and has no adjacent text. This might be, for example, an upward-pointing arrow icon in a <td>
in a “league table” where the arrow is intended to indicate a trend such as “The figure has increased” or “Moving up the table”.
The point here is that in this scenario the SVG is content rather than decoration.
<svg
role="img"
focusable="false"
aria-labelledby="arrow-title"
>
<title id="arrow-title">Balance has increased</title>
<path …>…</path
</svg>
Note: Fizz Studio’s article Reliable valid SVG accessibility suggests that the addition of aria-labelledby
pointing to an id for the <title>
(as Léonie originally recommended) is no longer necessary. That’s encouraging, but as it does no harm to keep it I think I’ll continue to include it for the moment.
The same article also offers that maybe we should not use the SVG <title>
element (and use aria-label
to provide an accessible name instead) due to the fact that it leads to a potentially undesirable tooltip, much like the HTML title
attribute does. To be honest I’m OK with this and don’t see it as a problem, and as I mention later have heard probably even more problematic things about aria-label
so will stick with <title>
.
Button (or link) with icon plus text
This is easy. Hide the icon from Assistive Technology using aria-hidden
to avoid unnecessary repetition and rely on the text as the accessible name for the button or link.
<button>
<svg aria-hidden="true" focusable="false" ><!--...--></svg>
Search
</button>
<a href="/search">
<svg aria-hidden="true" focusable="false"><!--...--></svg>
Search
</a>
Button (or link) with icon alone
In this case the design spec is for a button with no accompanying text, therefore we must add the accessible name for Assistive Technologies ourselves.
<button>
<svg focusable="false" aria-hidden="true"><!--...--></svg>
<span class="visually-hidden">Search</span>
</button>
<a href="/search">
<svg focusable="false" aria-hidden="true"><!--...--></svg>
<span class="visually-hidden">Search</span>
</a>
The reason I use text that’s visually-hidden using CSS for the accessible name rather than adding aria-label
on the button or link is because I’ve heard that the former option is more reliable. In greater detail: aria-label is announced inconsistently and not always translated.
References
- Accessible SVG Icons, by Chris Coyier;
- Tips for accessible SVG, by Léonie Watson;
- Reliable, valid SVG accessibility, by Fizz Studio;
- Accessible icon buttons, by Sara Soueidan;
- Every Layout’s Icon component; and
- How to hide elements on a web page, by my bad self.