Images Rule

Elements with role="img" must have alternative text role-img-alt

Adding role="img" to a div, span or any other element tells assistive technology to treat it as a single picture. That picture then needs a text alternative, exactly like an img needs alt. Without one, the element is announced as image and nothing more. Common cases are star ratings, CSS background images, emoji groups and icon fonts.

Websight reports this as [role="img"] and [role="image"] elements must have alternative text

Who it affects

Someone reading restaurant reviews with a screen reader reaches a star rating built from five span elements with role="img" and hears image, five times, never the score.

Someone with low vision using a screen reader alongside high zoom cannot make out a CSS background illustration and gets no spoken alternative to fall back on.

Someone using a braille display sees a blank graphic marker where a chart drawn with CSS should have been summarised in a sentence.

Broken versus fixed

Both examples are live and rendered in a sandboxed frame. The broken one is deliberately broken.

Broken

A screen reader reads: image. Some will read the raw star characters, black star black star black star black star white star, which is a puzzle rather than a score.

Fixed

Announced: Rated 4 out of 5 stars, image. One phrase, same meaning as the picture.

Show the markup behind both examples
Broken
<style>body{font-family:system-ui;padding:16px;margin:0}.row{display:flex;gap:12px;align-items:center}.stars{color:#e0a100;font-size:26px;letter-spacing:2px}</style>
<div class="row">
  <strong>The Copper Kettle, Harrogate</strong>
  <span class="stars" role="img">&#9733;&#9733;&#9733;&#9733;&#9734;</span>
</div>
<p>Lovely scones, slow service on a Saturday.</p>
Fixed
<style>body{font-family:system-ui;padding:16px;margin:0}.row{display:flex;gap:12px;align-items:center}.stars{color:#e0a100;font-size:26px;letter-spacing:2px}</style>
<div class="row">
  <strong>The Copper Kettle, Harrogate</strong>
  <span class="stars" role="img" aria-label="Rated 4 out of 5 stars">&#9733;&#9733;&#9733;&#9733;&#9734;</span>
</div>
<p>Lovely scones, slow service on a Saturday.</p>

Test it by hand in two minutes

  1. Open DevTools (F12), press Cmd+F or Ctrl+F in the Elements panel and search for role="img". Check each match has an aria-label, or an aria-labelledby that points at real text.
  2. Turn on VoiceOver (Cmd+F5) or NVDA and move through the page with the arrow keys. Each role="img" element should be announced as a short description followed by image.
  3. For a rating, chart or icon, ask whether the spoken words give the same information as the picture. Four stars should become something like 4 out of 5, not just stars.
  4. If the element is purely decorative, confirm it is skipped entirely rather than announced as image.

The fix

Before
<span role="img" class="stars">&#9733;&#9733;&#9733;&#9733;&#9734;</span>
After
<span role="img" class="stars" aria-label="Rated 4 out of 5 stars">&#9733;&#9733;&#9733;&#9733;&#9734;</span>

Put the meaning in aria-label, not a description of the glyphs. If the text already exists on the page, point at it with aria-labelledby instead of repeating it.

CSS background image that carries meaning

Before
<div role="img" class="map-pin"></div>
After
<div role="img" class="map-pin" aria-label="Entrance on Market Street"></div>

A background image has nowhere to put alt. role="img" plus aria-label is the right pair for it.

Decorative flourish

Before
<span role="img" class="divider"></span>
After
<span class="divider" aria-hidden="true"></span>

If it adds nothing, drop the role and hide it. Do not give decoration an empty aria-label and leave the role in place.

Group of emoji

Before
<span role="img">&#127968;&#128640;</span>
After
<span role="img" aria-label="Home and rocket emoji">&#127968;&#128640;</span>

Wrapping several emoji in one role="img" with a label stops each one being read separately.

Common mistakes

  • Adding role="img" to make an icon font announce properly, then forgetting the aria-label that was the point of it.
  • Writing aria-label="stars" or aria-label="icon", which names the picture type instead of its meaning.
  • Using alt on a span or div; alt only works on img, area and input elements.
  • Pointing aria-labelledby at an id that does not exist or at an empty element.
  • Giving a decorative element role="img" with an empty label instead of aria-hidden="true".

WCAG criteria this rule maps to

axe-core tags this rule as WCAG 2.2 level A. It is one of the checks for:

The scanner can see that an element with role="img" has no aria-label, no aria-labelledby that resolves to text, and no title. It cannot judge whether the label matches what the picture means. Automated tools find only part of the accessibility problems on a page; a pass on this rule is not a pass on the criterion.

Scan your own page for this and 63 other checks

Open any page in Chrome, click Websight, and get a score out of 100 with every issue explained and a draft fix snippet per element.

Add Websight to Chrome

Free scans, no account, nothing leaves your computer. Automated tools find only part of the problems; the extension says so on every report.