role=img Elements Need Alternative Text: How to Fix It

No Comments
Role=img elements need alternative text: how to fix it

This check fires when an element carrying role="img" has no accessible name — no aria-label, no aria-labelledby, nothing. You have told the browser "treat this as a picture," then handed the screen reader a picture with no caption. It gets announced as a bare, meaningless "image," or worse, its inner text nodes leak through in a garbled mess.

Why role="img" needs a name and a plain img usually doesn't

A normal <img> gets its accessible name from the alt attribute. But people apply role="img" to things that are not img elements — inline SVGs, icon-font <span>s, sprite <div>s, emoji clusters, ASCII art. Those elements have no alt attribute to fall back on. When you promote them to the image role, you take on the job of naming them yourself. Skip it and assistive tech has nothing to read out.

The role also does something sneaky: it tells the screen reader to ignore the element's children as content and treat the whole thing as one atomic image. So if you have a decorative icon font that renders a private-use glyph, and you add role="img" with no label, the user hears silence or a spoken code point. Rough.

Real failing example

<!-- Inline SVG rating stars, no accessible name -->
<span role="img">
  <svg viewBox="0 0 24 24" width="16" height="16"><path d="M12 2l3 7h7l-6 4 2 8-6-4-6 4 2-8-6-4h7z"/></svg>
  <svg viewBox="0 0 24 24" width="16" height="16"><path d="M12 2l3 7h7l-6 4 2 8-6-4-6 4 2-8-6-4h7z"/></svg>
</span>

<!-- Icon-font wrapper, announced as nothing useful -->
<i class="icon-cart" role="img"></i>

The star cluster is announced as "image" with no rating. The cart icon — a private-use font glyph — gets read as empty or as a raw character.

The fix

<span role="img" aria-label="Rated 2 out of 5 stars">
  <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path d="M12 2l3 7h7l-6 4 2 8-6-4-6 4 2-8-6-4h7z"/></svg>
  <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path d="M12 2l3 7h7l-6 4 2 8-6-4-6 4 2-8-6-4h7z"/></svg>
</span>

<i class="icon-cart" role="img" aria-label="Shopping cart"></i>

The aria-label becomes the accessible name. Marking the inner SVGs aria-hidden="true" stops their own guts from being announced twice. Note the label describes the meaning ("Rated 2 out of 5 stars"), not the mechanics ("two filled star shapes"). If the icon is purely decorative — it repeats adjacent visible text — drop the role entirely and add aria-hidden="true" instead of naming it.

Which naming method for which element

Element you gave role="img"Best naming methodAlso do
Inline <svg> iconaria-label on the role="img" hostHide inner shapes with aria-hidden="true"
Icon-font <span>/<i>aria-labelEnsure the glyph itself is not read
Sprite / background-image <div>aria-label or aria-labelledby
Emoji sequence (e.g. flags)aria-label describing the emoji meaningWrap in the role="img" span
Decorative, repeats nearby textNo name — remove role, add aria-hidden="true"Keep it out of the a11y tree

How to detect it

  1. axe DevTools. The svg-img-alt and role-img-alt rules flag any role="img" with no accessible name, and give you the exact selector.
  2. Lighthouse. The Accessibility audit "ARIA role="img" elements do not have an accessible name" lists every offender.
  3. Screen reader pass. Turn on VoiceOver (Cmd+F5 on macOS) or NVDA, arrow to the element, and listen. If it says "image" and nothing else, it is unnamed.
  4. Console query. document.querySelectorAll('[role="img"]:not([aria-label]):not([aria-labelledby])') returns every element missing a name.

How to fix it

  1. List every role="img" element from the console query above.
  2. For each, decide: is it meaningful or decorative?
  3. Meaningful → add an aria-label (or aria-labelledby pointing at existing visible text) describing what it conveys.
  4. Decorative → remove role="img" and add aria-hidden="true" so it stays out of the accessibility tree.
  5. Hide inner SVG/glyph nodes with aria-hidden="true" so nothing double-announces.
  6. Re-run axe to confirm zero role-img-alt violations.

Frequently asked questions

Can I use title instead of aria-label?

Not reliably. title produces a tooltip and its accessible-name support is inconsistent across screen readers, especially on non-interactive elements. Use aria-label or aria-labelledby; treat title as a bonus, never the primary name.

What's the difference between this and a plain SVG with no alt?

They overlap. A standalone <svg> intended as an image should carry role="img" plus a name, so the two checks often fire together. The broader SVG rules are covered in SVG Images and Graphics Require Accessible Text.

How long should the label be?

Long enough to convey the meaning, short enough not to annoy. "Shopping cart," "Rated 2 out of 5 stars," "Verified account." Describe purpose, not pixels. Overlong labels have their own downside — the same discipline as alt text over 100 characters.

Does this affect regular image SEO?

Search crawlers lean on real alt attributes on <img> for image indexing; role="img" plus aria-label is primarily an accessibility signal, not an image-search one. If you want the graphic in image search, use a genuine <img> with alt. Background on that is in the Alt Text glossary entry.

What if the icon already sits next to a text label?

Then it is decorative — do not name it twice. Remove the role and add aria-hidden="true". Duplicate announcements are as bad as missing ones. Related discernible-name logic lives in Links Must Have Discernible Text.

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

About SEO ProCheck

Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

Work With Me

Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

Subscribe to our newsletter!

More from our blog