Search topics
SVG icons with no name, or read out when they should be silent
An order list shows each order's status only as an inline SVG with no name, while the heading's decorative icon has its file name read out from a title element.
The problem
Screen reader users can't tell whether an order was delivered, and hear icon file names instead.
An online shop's account page has a heading, "Your orders", with a small parcel icon in front of it. Below it are three orders. Each row gives the order number and date, and ends with a coloured icon: a green tick, a blue truck or a red circle with an exclamation mark. A sighted shopper sees at a glance that one order arrived, one is on its way and one payment failed. A screen reader reads "icon-package Your orders, heading", then "Order 1042, 3 October, image", "Order 1043, 6 October, image" and "Order 1044, 8 October, image". Some screen readers say nothing at all for the icons. The one thing the list is for, the status, never reaches the listener.
All the icons come from the same icon set, which inlines each one as an <svg>. The status icons were given role="img" so screen readers would treat them as images, but no name, so they are announced as an image with nothing to say. The parcel icon was not meant to say anything, yet the set puts a <title>icon-package</title> inside every SVG, and a heading takes its name from its content, title included. So the icon that should be silent is read out, and the icons that should speak are silent. Both break 1.1.1: meaningful non-text content needs a text alternative, and decorative content must be hidden from assistive technology.
The status icons are also coloured, but the colour is not the problem here: each icon has its own shape. The problem is that neither the shape nor the colour exists in text.
2 of 10 groups affected
- No vision (affected)
- Low vision (not affected)
- Colour vision (not affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (not affected)
- Reach, strength (not affected)
- Cognitive (affected)
- Seizures (not affected)
- Without vision Screen reader users hear “image”, or nothing, where each status is shown, so they can't tell a delivered order from a failed payment. They also hear the heading's icon file name before the heading itself.
- Limited language, cognitive and learning abilities People who don't know what a truck or a circle with an exclamation mark stands for have only the icon to go on when the status is never written in words.
axe's svg-img-alt and role-img-alt flag an SVG with role="img" and no name, so the status icons are caught. They don't flag an SVG with no role at all, which some browsers skip and others expose as a group, and they don't notice the parcel icon: it is inside a heading that has a name, so nothing looks wrong, even though "icon-package" is read out. A quick AI fix often names each icon after its shape ("check", "truck", "warning") because that is what the file is called, or hides all the icons to silence the scanner, which removes the status completely. Only someone who knows what each icon means in this list can say what its name should be, and whether it needs one.
Try it
Compare what you see with what a screen reader reads.
The panel shows what a screen reader reads, top to bottom. Can you tell which order arrived and which payment failed?
Broken Can you fix this?
Your orders
- Order 1042 3 October
- Order 1043 6 October
- Order 1044 8 October
A screen reader reads:
- icon-package Your orders, heading
- list, 3 items
- Order 1042, 3 October, image
- Order 1043, 6 October, image
- Order 1044, 8 October, image
A recreated demo. The broken version is intentionally inaccessible.
The fix
Name every SVG that carries meaning, and hide every SVG that doesn't with aria-hidden="true".
- 1Every inline SVG is named or hidden, never left in between.
- 2Name the icon's meaning here, as an aria-label or as visible text beside a hidden icon, not its shape.
- 3Hide decorative icons with aria-hidden="true", and remove the title they came with.
Not enough on its own. Meets 1.1.1 for screen reader users, but the status is still shown only as an icon, so sighted people who don't know what a truck or an exclamation mark stands for still have to guess.
<h2> <svg viewBox="0 0 24 24"><title>icon-package</title>…</svg> Your orders</h2><ul class="orders"> <li> Order 1042 <span class="date">3 October</span> <svg role="img" viewBox="0 0 24 24" class="ok">…</svg> </li> <li> Order 1043 <span class="date">6 October</span> <svg role="img" viewBox="0 0 24 24" class="info">…</svg> </li> <li> Order 1044 <span class="date">8 October</span> <svg role="img" viewBox="0 0 24 24" class="error">…</svg> </li></ul>The status icons are images with no text alternative, so the status is lost. The parcel icon adds nothing, but its title is read as part of the heading.
Each status icon keeps role="img", so it is exposed as one image, and gains an aria-label that says what it means for this order. A screen reader reads "Order 1042, 3 October, Delivered, image". The parcel icon loses its title and gets aria-hidden="true", so the heading is read as "Your orders". The page looks exactly as before, and that is its limit: the status reaches screen readers in words, but on screen it is still only an icon. Someone who doesn't know that the truck means "on its way", or who reads the red circle as an error with the site rather than with their payment, is left to guess. No A or AA criterion requires the words to be visible, but W3C's guidance on making content usable for people with cognitive disabilities asks for text alongside icons.
Both options give each status a text alternative and silence the decorative icon, so both meet 1.1.1. Naming the icons changes only attributes and keeps the design as it is, but its words exist only for assistive technology: some page translators skip aria-label, and sighted people still have to know what each icon means. Writing the status as text is plain HTML, works for everyone who reads the page and leaves nothing for ARIA to carry; its only cost is room in the row. Use it. Keep named icons for the rare place with truly no room for words, such as a dense table, and then only with icons your users already know, with a visible legend nearby.
Name or hide, never neither. An inline SVG with no role and no aria-hidden is treated differently by each browser and screen reader: some skip it, some announce "group" or "image", and some read its <title> or text. Decide for every icon, and make the decision in the shared icon component: give it a label prop that, when set, adds role="img" and aria-label, and otherwise adds aria-hidden="true".
Titles from the icon set. Many icon sets and design exports put a <title> with the file name in every SVG. Remove it, or replace it with the meaning. A <title> can name an SVG (role="img" aria-labelledby pointing at it), but it also shows as a tooltip in some browsers, and a title left inside a hidden icon does nothing, so aria-label is the simpler choice.
SVGs loaded with img or CSS. An icon in <img src="tick.svg"> follows the image rules: alt="Delivered" or alt="". An icon drawn with a CSS background or a mask is invisible to assistive technology, so its meaning must be in the text. An icon font glyph inserted with ::before may be read as a strange character; put it in an element with aria-hidden="true".
Icons in buttons and links. An icon that is the only content of a button or link is part of that control's name, so the name goes on the control and the icon is hidden. See the guide on icon-only buttons.
Contrast and forced colors. An icon that carries meaning needs 3:1 contrast against its background under 1.4.11. Draw icons with fill="currentColor" or stroke="currentColor" so they follow the text colour in forced colors mode instead of disappearing.
focusable="false". Old versions of Internet Explorer put every SVG in the tab order, and many icon sets still add focusable="false". It does no harm and is no longer needed.
Fixing this with an AI coding assistant? Get this guide as Markdown
Verify the fix
4 checks, no mouse.
Test with: Screen reader, Forced colors
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat whenever the icon set or the shared icon component changes.
Limits
This is a starting pattern, not a guarantee for every application. Paths, class names and the … in the SVGs are placeholders. Screen readers announce named SVGs in slightly different ways, and some still read an unnamed one, so test with the assistive technology your users have. Whether an icon is decorative depends on what the text around it already says, and only someone who knows the page can judge that. Test the complete journey with your target assistive technology.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.