# SVG icons with no name, or read out when they should be silent

Source: https://easeweb.dev/learn/svg-icons
Topics: Images and media > SVG icons have a name or are hidden (WCAG 1.1.1)
The fix: Decide for every inline SVG whether it carries meaning, then name it or hide it. Either name each meaningful icon with role="img" and an aria-label, or write its meaning as visible text beside it and hide the icon with aria-hidden="true". Decorative icons get aria-hidden="true" in both.
Test with: screen reader, forced colors
References: https://www.w3.org/WAI/WCAG22/Understanding/non-text-content.html https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA6 https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA24 https://www.w3.org/TR/svg-aam-1.0/ https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/img_role https://www.w3.org/TR/coga-usable/

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.

## What happens

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.

## Why it fails

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.

## Who is affected

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.

## What automation and AI miss

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.

## Before: status icons with no name, and a decorative icon with a title

```html
<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.

## After: name each status icon

```html
<h2>
  <svg viewBox="0 0 24 24" aria-hidden="true">…</svg>
  Your orders
</h2>
<ul class="orders">
  <li>
    Order 1042 <span class="date">3 October</span>
    <svg role="img" aria-label="Delivered" viewBox="0 0 24 24" class="ok">…</svg>
  </li>
  <li>
    Order 1043 <span class="date">6 October</span>
    <svg role="img" aria-label="On its way" viewBox="0 0 24 24" class="info">…</svg>
  </li>
  <li>
    Order 1044 <span class="date">8 October</span>
    <svg role="img" aria-label="Payment failed" viewBox="0 0 24 24" class="error">…</svg>
  </li>
</ul>
```

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.

## After: write the status as text and hide the icons

```html
<h2>
  <svg viewBox="0 0 24 24" aria-hidden="true">…</svg>
  Your orders
</h2>
<ul class="orders">
  <li>
    Order 1042 <span class="date">3 October</span>
    <span class="status ok">
      <svg viewBox="0 0 24 24" aria-hidden="true">…</svg> Delivered
    </span>
  </li>
  <li>
    Order 1043 <span class="date">6 October</span>
    <span class="status info">
      <svg viewBox="0 0 24 24" aria-hidden="true">…</svg> On its way
    </span>
  </li>
  <li>
    Order 1044 <span class="date">8 October</span>
    <span class="status error">
      <svg viewBox="0 0 24 24" aria-hidden="true">…</svg> Payment failed
    </span>
  </li>
</ul>
```

```css
.status { display: inline-flex; align-items: center; gap: 6px; }
.status svg { width: 20px; height: 20px; flex: none; }
```

The status is now written in words beside each icon, so every icon is decorative and gets `aria-hidden="true"`. A screen reader reads "Order 1042, 3 October, Delivered", with no "image" in between, and a shopper who doesn't know what the truck means can read it. The words are translated with the page and enlarge with the text.

## Which option to use

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.

## Implementation decisions

**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.

## Verify the fix

1. In the browser's accessibility tree, check that each status icon is an image named "Delivered", "On its way" or "Payment failed", or is absent with its status present as text, and that the parcel icon does not appear and the heading's name is "Your orders".
2. With a screen reader, read the list from the heading down. Each order's status should be read once, in words, with no file name, no icon shape and no "image" on its own.
3. Ask someone who can see the icons to compare each name or text with its icon, and confirm that every status shown is also said, and that the words say what the status means, not what the icon looks like. Where the icons are only named, also check that the people who use the page know what each icon means without being told.
4. Turn on forced colors (Windows Contrast themes) and check that every status icon, or the words beside it, is still visible.

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.
