( Perceivable / WCAG 1.1.1 )
role="img" element has no accessible text
What is this issue?
role="img" is an ARIA role that tells assistive technology to treat a container element as a single image, collapsing whatever is actually inside it (often several meaningless icon-font characters) into one announced unit. This element has the role but no accessible name, the text a screen reader announces to identify an element, coming from the first source that applies: aria-labelledby, then aria-label, then visible text, then other fallbacks specific to the element type.
Neither aria-label nor aria-labelledby is present. Assistive technology knows it has reached “an image,” because the role says so, but has no text to say what that image is.
Why does this matter?
role="img" shows up most often wrapping icon fonts, where a webfont glyph is the only thing conveying a piece of information, such as a star-rating widget built from five <span> elements, a status dot, or a severity flag. Without a label, the visual meaning that glyph carries for sighted users simply doesn’t exist for anyone using a screen reader.
A product page showing a 4.5-star rating built from five icon-font stars with no label announces as five unlabeled images in a row, or, in some screen readers, nothing at all, since an empty accessible name can cause the element to be skipped entirely. A sighted shopper glances at the stars and instantly knows the rating; a screen reader user gets no equivalent signal unless the surrounding page happens to restate it in visible text.
Who is affected?
- Screen reader users: reach an element announced only as “image” or “graphic,” or hear nothing at all if the accessible name resolves to empty, with no way to recover the rating, status, or icon meaning the glyph was meant to convey.
What users experience
Fatima uses JAWS on Windows to compare products on an online store. Each product card shows a star rating built from icon-font glyphs wrapped in <span role="img"> with no label. JAWS announces “graphic” five times in a row for each product, with no number and no context. She has no way to tell a 2-star product from a 5-star one without opening each listing individually and hoping the exact rating appears somewhere in visible page text.
How do I fix it?
Add aria-label to the role="img" element, summarizing what it depicts as a short phrase, such as “4.5 out of 5 stars,” not “star icon.” This works because aria-label gives assistive technology one clean accessible name for the whole grouped element, replacing whatever meaningless glyph characters or repeated child elements it would otherwise try to announce individually.
If visible text nearby already states the same information (a number next to the star row, like “4.5 (128 reviews)”), use aria-labelledby pointing at that text instead of writing a duplicate aria-label. Reusing existing text keeps the rating consistent for sighted and non-sighted users without maintaining two copies of the same fact.
Code Examples
<span role="img" class="icon-star icon-star icon-star icon-star-half"></span><!-- Method 1: aria-label (most common, no visible text to reuse) -->
<span role="img" aria-label="4.5 out of 5 stars" class="icon-star icon-star icon-star icon-star-half"></span>
<!-- Method 2: aria-labelledby (when the number is already shown visibly) -->
<span role="img" aria-labelledby="rating-text" class="icon-star icon-star icon-star icon-star-half"></span>
<span id="rating-text">4.5 out of 5 (128 reviews)</span>The aria-label version writes the description once, directly on the element that needs it, the simplest fix when nothing else on the page already states the rating. The aria-labelledby version is worth the extra step whenever a sighted-visible number already exists, since it guarantees the announced value and the displayed value can never drift apart.
Common Mistakes
Mistake: “Icon fonts are decorative, so I don’t need to label them.” An icon font glyph is decorative only when it adds nothing beyond what’s already stated elsewhere. A star-rating icon row is the sole way the rating is conveyed to a sighted user, which makes it informative, not decorative: informative content needs a label, decorative content needs aria-hidden="true", and mixing up which one applies is the root cause of this rule.
Mistake: “The rating number is right next to the icons, so the icons don’t need their own label too.” If visible text already states the rating, the correct fix is aria-labelledby pointing at that text, or aria-hidden="true" on the icon row so it doesn’t announce twice, not a second, separately-worded aria-label that risks contradicting the visible number over time.
Mistake: “role="img" only applies to actual <img> or <svg> elements.” The role can be applied to any HTML element. Its most common real-world use is exactly the opposite of an <img> tag: grouping several non-image child elements, like icon-font glyphs, into one unit that assistive technology treats as a single image.
Mistake: “A title attribute is a safe substitute for aria-label here.” title only appears as a mouse-hover tooltip in most browsers, so keyboard-only and touch users never see it, and screen reader support for reading it as a name is inconsistent. Use aria-label or aria-labelledby, not title, as the accessible name source.
How RedFlag Detects This
Automated: axe-core rule, runs on every scan. RedFlag calls axe-core’s role-img-alt rule as part of every scan, restricted to the WCAG 2.0/2.1/2.2 A and AA rule set. The rule inspects every element carrying an explicit role="img" attribute (excluding native <img> and <svg> elements, which are covered by the separate image-alt and svg-img-alt rules) and checks whether it resolves a non-empty accessible name through aria-label or aria-labelledby.
False negative: axe-core confirms a name exists; it cannot judge whether the name is accurate. aria-label="icon" on a five-star rating widget passes the automated check even though it tells a screen reader user nothing about the actual rating. False positive: none typical for this check, since resolving to a non-empty accessible name is a binary condition axe-core evaluates reliably. Manual step: read the announced label against what the icon or icon group actually conveys, and confirm it states the real value, not just a generic placeholder.
Manual Testing
- Open the page in Chrome or Firefox with NVDA or VoiceOver running.
- Navigate to the
role="img"element using the screen reader’s element list or browse mode (NVDA: Insert+F7, filtered to Graphics; VoiceOver: the Rotor, filtered to Images). - Listen to what’s announced; it should be a specific, accurate description of what the icon or icon group represents, not just “image” or “graphic” with nothing else.
- If the element announces nothing at all, or only the generic role with no name, the check fails.
Related WCAG Success Criteria
1.1.1 Non-text Content: All non-text content must have a text alternative that serves the equivalent purpose. An unlabelled role="img" element is a direct failure of this criterion: the role marks it as image content, but no text alternative exists.
4.1.2 Name, Role, Value: Every interface component must expose a name, role, and value to assistive technology. A role="img" element without an accessible name has a role but no name, which is a 4.1.2 failure alongside the 1.1.1 failure.
Related Issues
Image is missing alt text is the equivalent failure on a native <img> element instead of a role="img" container: same missing-text-alternative problem, different element.
SVG image has no accessible label covers the same naming gap when the image content is an inline <svg> rather than an icon font wrapped in role="img".
Object element has no text alternative and Image input is missing alt text cover the same missing-name failure on two other non-text element types axe-core checks separately.
Image map area element is missing alt text is the equivalent failure inside a client-side image map’s clickable regions.
References
- W3C Understanding 1.1.1: Non-text Content
- W3C Technique ARIA6: Using aria-label to provide labels for objects
- MDN: img role
Frequently asked questions
Does role="img" work on any HTML element, or only on img and svg?
It works on any element. The most common use is a span or div wrapping one or more icon-font glyphs, where role="img" tells assistive technology to treat the whole group as a single image instead of announcing each glyph character separately.
Should decorative icon fonts use role="img" too?
No. role="img" tells assistive technology this element is meaningful content that needs a name. A purely decorative icon should use aria-hidden="true" instead, which removes it from the accessibility tree entirely rather than giving it an empty or generic name.
Is this the same check as svg-img-alt?
No, they are separate axe-core rules covering different elements. svg-img-alt checks inline svg elements specifically; role-img-alt checks any other element carrying an explicit role="img" attribute, most often a span or div built from an icon font.
Does aria-labelledby work as well as aria-label on a role="img" element?
Yes, and it is often the better choice. If visible text near the icon already states the same information, such as a number shown next to a star-rating icon row, point aria-labelledby at that text instead of duplicating it in a separate aria-label.
Will axe-core catch a role="img" element that has an aria-label with meaningless text?
No. Automated checks confirm an accessible name exists; they cannot judge whether that name accurately describes the image. aria-label="icon" technically passes the check while telling a screen reader user nothing useful.