By using ARIA’s role="img" you can change the semantics of an element to expose itself to the browser’s accessibility API as an image or “graphic”.

While the best course of action is to not do this, and use an img or svg elements instead, there may be situations where you may need this role.

For instance, maybe you are using font icons rather than SVGs. When applicable, you can expose these icons as graphics by giving them a role="img" and an accessible name via aria-label:

<p>
  Get the latest update!

  <a href="..." download>
    <span class="download-icon-class" 
      role="img" 
      aria-label="Download the update"></span>
  </a>
</p>

The drawback is no fallback

In ideal situations an element with role="img" and aria-label="..." will be just as accessible as a native <img alt="...">. However, in instances where the asset providing the “image” is blocked or broken the aria-label won’t automatically become visible. The element will still have the semantics of an image and its accessible name, from the ARIA attributes, but will likely be inaccessible to people not using a screen reader.

Consider the following:

buttons with font icons. Left button shows icon rendering. Right button shows icon failed to render, and button collapses on itself.

When an icon delivered by JavaScript and CSS loads, everything is fine. But without, the button visually deflates (literally, its barely visible in the screen shot).

While a hiccup in JavaScript or CSS delivery can be unfortunate but temporary, similar failures can be triggered by the manner in which people want to interact with your content.

Consider the following example and how it would render in a browser’s reader mode:

<p>
  Your score has gone 
  <span class="icon-up" role="img" aria-label="up"></span> 
  10 points.
</p>

Judging by the code snippet you might imagine that some kind of “up arrow” icon preceding the “10 points” text. When a browser goes into reader mode, author defined CSS and JavaScript are stripped, resulting in the icon not loading, and presenting sighted users with the following:

Your score has gone 10 points.

Get your dev tools out, or take a 50/50 chance of guessing the direction there without the visual cue.

Solutionizing

Again, the most robust solution for providing graphics that are meant to convey information is to use actual image or SVG elements.

As far as alleviating the text fallback issue for role="img", presently the following pattern seems like it could be used as a good baseline:

<style>
  [role="img"] span {
    display: none;
  }
</style>

<span role="img" aria-labelledby="id_ref">
  <span id="id_ref">oh hi there</span>
</span>

At least, this is what we’d want the final output to be. aria-labelledby can point to the id of content that is otherwise completely hidden from all users (e.g. display: none), so there would be no duplicate announcements of the image’s accessible name.

If CSS were to be blocked (again, reader mode), the display: none would not apply anymore and the child content would be revealed. The snippet would still have a role="img" if that were hard coded though. And gosh, people rightfully hate manually providing elements unique IDs…

Taking this a step further, I built a little demo to show how spans could be progressively enhanced into role="img"s that use aria-labelledby to point to their accessible names.

See the Pen provide role=img with accessible names by Scott (@scottohara) on CodePen.

With this demo, if JavaScript fails or is blocked, then no role=img is provided, and the CSS to hide the accessible name won’t trigger.

Will a solution like this work for you? I dunno, maybe? But I’m pretty sure that if this doesn’t, a real image or SVG would!

Another gap for consideration

In running some quick tests with different browser and screen reader pairings for role=img patterns, it appears that JAWS 2019 presently has a bug where role=img elements are ignored in IE11. If you need to continue supporting this browser, this gap should definitely be taken into consideration.