Before we begin, I want to level set that this is not an article about why you need to make images and SVG elements accessible. There are plenty of great resources already out there that provide excellent guidance, and I will include links to some of them in the further reading section at the end this article.

What this article is about is that there are various methods that can be used to provide an accessible name to an image or SVG element. Those being:

  • An image’s alt attribute.
  • A SVG’s child title element.
  • Using aria-label or aria-labelledby on an image or SVG.
  • Using a title attribute on an image or SVG.

However, depending on the markup pattern and the method used, the accessible name may not be exposed as expected, due to quirks or gaps in implementations. This means that without testing, graphics may not be exposed in the manner in which you might expect.

Additionally, this article will outline why different markup patterns are necessary when using images or SVG elements within interactive elements, such as links and buttons.

Examining different scenarios

In researching for the most robust patterns to markup graphics, I tested with different browsers and paired them with different screen readers on desktop and mobile devices:

Listing of tested browser & screen reader pairings
  • macOS VoiceOver with Safari and Chrome
  • Narrator with Edge
  • NVDA with IE11, Firefox, Chrome and Edge
  • JAWS with IE11, Firefox, Chrome and Edge
  • TalkBack 7.2 on Android 8.1.0 with Chrome and Firefox
  • iOS VoiceOver with Safari

Note: all Windows testing was performed on a Windows 10 machine.

Testing the image element

The image element has been around awhile now, so you may be wondering why I’d go to the trouble of testing the accessibility of such a fundamental part of the web. It turns out that depending on how you intend to use the element, and what file format you use as its source, you may create behaviors you weren’t anticipating.

Images that convey information

For raster graphics that are used to convey useful information, using the alt attribute is the best way to convey the accessible name of the image element.

<img src="my-image.jpg" alt="Accessible Name">

The alt attribute is recommended over other attributes that would provide an accessible name. While title, aria-label, and aria-labelledby attributes could also provide an image element with an accessible name, only alt will consistently render fall back text if an image were to break or be blocked.

Notes on image fall back text

As of publishing, Internet Explorer 11, pre-Chromium Edge and Firefox do not render title attribute text for broken images.

Chrome and Safari will render fall back text for alt and title attributes. However, Safari will only show the fall back text if the image also has a defined fixed or minimum height and width which would provide enough visible space for the text to appear on screen. In other words, no set height and width on the image means no fall back text will be rendered.

If both title and alt attributes are used, the alt will be the fall back text that is rendered.

See the Pen Broken Image tests by Scott (@scottohara) on CodePen.

Image elements with SVG source exception

A quirk to be aware of is using a .svg file as the source for an image element. Consider the following:

<img src="my-file.svg" alt="hi">

Desktop Safari and VoiceOver will announce “hi, group” with no announcement of the element being an “image”. However, what’s more problematic is that iOS Safari and VoiceOver will skip over the element all together, as if it were decorative.

Providing an image element with a role="img" will announce the “image” role as intended with macOS Safari, and fix it from being ignored on iOS. You’ll get some automated testing tools throwing warnings for the redundant role, but that’s better than it being incorrectly announced or ignored, in my opinion.

An issue was filed with WebKit in July 2018 due to this behavior. Please feel free to ask for it to be prioritized.

Image elements that are decorative

Graphics that serve as decoration to accompanying text should often be ignored by screen readers to help reduce unnecessary or redundant information. For image elements, the following markup can be used to make screen readers ignore decorative graphics:

<img src="img.jpg" alt="">
<!-- or -->
<img src="img.jpg" alt>

Prior to macOS 10.14.4, aria-hidden="true" would also be necessary to completely hide a decorative image to VoiceOver when paired with Chrome. Without the ARIA attribute, VoiceOver would still focus the image, but provide no announcement. Review your own analytics and perform your own testing to determine if this extra precaution is applicable to you.

In a situation where both a graphic and visible label are children of a link, the image within the link can be considered decorative. This is because we don’t want to produce duplicate announcements for a link.

For example, the following would announce “Search” twice, and then likely announce the “graphic” or “image” role, accompanying the “link” role. The announcement would depend on the screen reader being used.

<!-- don't do this -->
<a href="#urlHere">
  <img src="fileName.fileType" alt="Search">
  Search
</a>

Giving the image element an empty alt will treat it as decorative content. The visible text will provide the accessible name to the link:

<a href="#">
  <img src="fileName.fileType" alt="">
  Search
</a>

In a situation where a graphic alone visually represents a link, there’s no need to add visually hidden text, or to use ARIA attributes to provide the link’s accessible name. The following markup pattern will provide the link with the accessible name, “search”, with each tested browser and screen reader pairing:

<a href="#urlHere">
  <img src="fileName.fileType" alt="Search">
</a>

This pattern will allow screen readers to quickly access the element if navigating by links, or by graphic elements, with one exception. Chrome paired with JAWS 2019 (April) will not be able to navigate to this pattern when using the graphic hot key.

Image elements within buttons

One would be correct to assume that an image alone that provides the accessible name to a button should be no different than the markup used to provide an accessible name to a link. However, assumptions are exactly why I performed these tests…

<!-- should be able to use this... -->
<button>
  <img src="fileName.fileType" alt="Accessible Name">
</button>

Presently, with pre-Chromium Microsoft Edge, a bug exists where the accessible name of the button is not exposed if provided by an image element’s alt attribute. Until Edge is updated to be powered by Chromium, one of the following patterns can be used to mitigate this gap, while also maintaining a consistent accessible name announcement in other browser and screen reader pairings.

Option 1

<!-- provide a title attribute as well -->
<button>
  <img src="icon.fileType" alt="Accessible Name" title="Accessible Name">
</button>

In this pattern, the title attribute will stand in for Edge not recognizing the image element’s alt attribute. As long as the title is exactly the same (content and capitalization) then all other screen reader and browser pairings will continue to announce the button as expected. You can read more about the quirks (and UX gaps) of the title attribute in my article The Trials and Tribulations of the Title Attribute.

Option 2

<!-- or use ARIA -->
<button aria-label="Accessible Name">
  <img src="icon.fileType" alt="">
</button>

As children of button elements are meant to have their semantics set to presentational, graphics within buttons are not meant to be discoverable elements. That being the case, an aria-label attribute could be set to the button, and the graphic could be considered decorative. However, aria-label may not be ideal, as in the event an image breaks, no fallback content would be displayed in the button element.

Option 3

Adding text along with a decorative graphic to the button:

<!-- display the accessible name with the icon -->
<button>
  <img src="icon.fileType" alt>
  Accessible Name
</button>

In this example, the accessible name for the button is provided by the visible text. Because of this the graphic can be considered decorative, and no additional attributes would be necessary.

Additionally, the text could be visually hidden if the button needed to be visually represented by the graphic alone.

<!-- use CSS to hide the text of the button -->
<button>
  <img src="icon.fileType" alt>
  <span class="sr-only" role="presentation">Accessible Name</span>
</button>
Note about using .sr-only within interactive elements

Adding display: block (or position: absolute as the sr-only class uses) can create multiple virtual cursor focus stops for buttons and links with some screen readers.

Adding a role="presentation" to the child element(s) with the sr-only class will help make sure the virtual cursor does not stop multiple when using the Up arrow or Down arrow keys to navigate to or through an interactive element.

Testing the <svg> element

These tests treated SVG and image elements as similar types of content (graphics providing meaningful content or being used for decoration). However, SVGs fundamentally require different markup patterns to the image element, and thus necessitated different tests to be run.

In contrast to raster images, SVGs can have child elements like <title>, <text>, <image>, <desc> which all may be used in exposing information to assistive technologies. Regarding the scope of these tests, only <title> elements were used in the markup patterns they appear in.

For additional testing information on SVGs, which go beyond what I was looking to verify, please review Creating Accessible SVGs by Carie Fisher, SVG Icons and Screen Reader Accessibility (slideshare), by Dennis Lembree, and Accessible SVG flowcharts, by Léonie Watson, for starters.

With that said, let’s look at the patterns tested:

SVGs that convey information

The following pattern was one of the most robust in appropriately announcing an SVG an “image” or “graphic” with an accessible name. You might use this if marking up a logo or illustration that provides meaning to a document:

<svg role="img" focusable="false">
  <title>Accessible Name</title>
  <use xlink:href="#svg-id-to-reference" aria-hidden="true" />
  <!-- if not using <use> then the child elements 
       of the inline SVG would go here -->
</svg>

This pattern will properly announce the SVG as an “image” or “graphic” in all tested screen reader and browser pairings. Its accessible name will be properly announced, and it is even revealed as a native HTML tooltip on mouse hover.

If a native HTML tooltip is not desired, the following markup pattern could be used instead:

<svg role="img" aria-label="Accessible Name" focusable="false">
  <use xlink:href="#..." aria-hidden="true"></use>
</svg>

Adding aria-hidden="true" to <use> stops some screen readers from making redundant announcements, or announcing a <title> element that may be an unwanted child of the referenced SVG, or in some cases, causing a bug where the accessible name is ignored all together!

It’s worth noting that SVGs are often exported from graphics programs with unhelpful <title>s (“Created by Sketch” is not helpful to anyone, thank you). Cleaning up your exported SVG <title> elements should be considered a necessary task in your organization’s workflow.

If an SVG’s code is fully inlined, then unnecessary child elements and content should be optimized away. paths and any other direct child elements of the SVG should receive an aria-hidden="true" if they contain no information that should be made accessible.

SVGs that are decorative

A SVG that does not add important information to a document should be considered decorative. The following markup pattern uses aria-hidden="true" to hide the SVG from screen readers. focusable="false" is also used to ensure Internet Explorer won’t allow the Tab key to navigate into the SVG.

<svg aria-hidden="true" focusable="false">
  <!-- ... --> 
</svg>

Since the SVG is meant to be hidden, there’s no need to add a role attribute, as it would be ignored anyway.

Note that while some screen readers may ignore an SVG if it has no role or accessible name, other screen readers may still find the element and announce it as a “group” without an accessible name. It’s best to avoid these situations by always using aria-hidden="true" if the SVG is meant to be decorative.

When attempting to use the SVG patterns that had the fewest issues, to provide links and buttons with their accessible names, it became clear that what worked outside of interactive elements would not necessarily work within.

Take for example a pattern that performed very well as stand alone content, with exceptions noted only for JAWS paired with Internet Explorer 11 (exceptions noted in test results, linked to at the end of this article):

<a href="#!">
  <svg role="img" aria-label="Accessible Name" focusable="false">
    <use xlink:href="#..." aria-hidden="true"></use>
  </svg>
</a>

However, when using this same pattern within a link or button, different gaps and failures occurred. More troubling, was that the gaps were different depending on if the pattern was a child of a button or link.

Using the SVG within a button

The noted SVG pattern passed all tests, except when using Microsoft Edge. With Edge, the SVG failed to provide a button with an accessible name, regardless of screen reader pairing. Remember that bug I mentioned about Edge not recognizing an image element’s alt value? Here we are again…

The bright side(?) here is that when Chromium-Edge is publicly released, this failure will likely go away. When that happens, this particular pattern would have full support across all browsers and screen readers tested.

Unfortunately, SVGs within links fared a bit worse. Unlike the button example which was problematic only with current Edge, SVGs within links do not communicate accessible names with IE 11 paired with NVDA, or current Edge paired with JAWS.

Additionally, the pattern resulted in JAWS not being able to navigate to the link/SVG if paired with IE11 or Chrome.

To ensure that links and buttons containing SVGs will be accessible, regardless of the screen reader and browser pairing used, it may be best to provide accessible names via other means, and treat the SVG as decorative.

A consistent SVG markup pattern to consistently provide links and buttons an accessible name is far superior than implementing a pattern with gaps.

For example, the following would use the element’s visible text to provide the accessible name:

<button>
  <svg focusable="false" aria-hidden="true"><!--...--></svg>
  Search
</button>

<a href="/search">
  <svg focusable="false" aria-hidden="true"><!--...--></svg>
  Search
</a>

If the elements’ intended designs called for using the graphics alone, visually hidden text could be used:

<button>
  <svg focusable="false" aria-hidden="true"><!--...--></svg>
  <span class="sr-only">Search</span>
</button>

<a href="/search">
  <svg focusable="false" aria-hidden="true"><!--...--></svg>
  <span class="sr-only">Search</span>
</a>

Or an aria-label set to the link or button element would achieve the same effect (and btw, aria-label should be translatable now with Google Translate!):

<button aria-label="Search">
  <svg focusable="false" aria-hidden="true"><!--...--></svg>
</button>

<a href="/search" aria-label="Search">
  <svg focusable="false" aria-hidden="true"><!--...--></svg>
</a>

For more detailed information about providing accessible names to interactive elements when using SVGs, I’d recommend reading Sara Soueidan’s post, Accessible Icon Buttons, as well as the links mentioned in the further reading section.

Wrapping Up

I started writing this article and performing these tests at the end of 2018. Clearly, I took some time to finish them all up. But the reason I mention this is because during that time span there were many releases to browsers and screen readers alike. The time gap was actually favorable to some tests. And as I’ve noted already, Edge is on the cusp of being re-released with a completely different engine under the hood, results are about to get more… uniform at least.

It is worth noting that these test results, and the patterns I’ve identified as providing the most robust support, are representative of a snapshot in time. The advice I will give time and time again is to test the markup patterns you’re using and ensure the intended information is being communicated to all users.

I’m looking forward to writing future updates to this article, and noting any fixed bugs, and updated support for the markup patterns. But for now, here are links to the tests and results these findings were based on:

Further reading

As I mentioned at the beginning of this article, here are some links to additional resources to check out. Many of them go into far greater / different details about similar patterns, and why providing accessible names to graphics (and their parent elements) is so important:

Some shout outs

Thank you to Steve Faulkner for reminding me about child elements of buttons inheriting role=presentation, to Patrick H. Lauke for test result feedback, Eric Bailey for reviewing this article, and to Sara Soueidan for encouraging me to finish the work I had started. This article would have likely continued to sit on the back burner without all of you.