An icon is rendered as inline SVG markup rather than as an img element. What markup makes a screen reader announce it as an image with a name, and what do you do when the same icon is decorative?
answer
- no alt attribute exists here
- declare it one image, then name it
- native title element must come first
- decorative means removed, not renamed
- name the control, hide the graphic
basics
~20 sAn inline svg has no alt attribute. Give a meaningful one role="img" plus aria-label (or an svg title element as the first child) so it is announced as a named image; give a decorative one aria-hidden="true" so it is skipped entirely.
solid answer
~50 sInline `<svg>` is not an `<img>`, so there is no `alt` attribute to reach for and its shapes may otherwise leak into the accessibility tree as unnamed nodes. For a meaningful icon the robust recipe is `role="img"` on the `<svg>` plus `aria-label` carrying the text alternative; the SVG `<title>` element as the first child of `<svg>` is the native equivalent and many teams supply both, because `role="img"` collapses the internal shapes into a single image node. For a decorative icon — one sitting next to a visible text label that already says the same thing — put `aria-hidden="true"` on the `<svg>` and it is skipped, exactly as `alt=""` does for an `<img>`. The most common mistake is an icon-only button where the label is attached to the SVG rather than to the `<button>`; the accessible name belongs on the control, and the icon inside it is decorative.
go deeper
Remember that inline <svg> has no alt. Be able to say that a meaningful icon needs role="img" with aria-label, and a decorative one needs aria-hidden="true".
Explain what each piece does: role="img" collapses the subtree into one image node, aria-label supplies the alternative, the SVG <title> element is the native equivalent and must be the first child, and aria-hidden removes the element the way alt="" does for an img.
Show the judgement about placement — the accessible name belongs on the interactive element, and the icon inside it is decoration. Be ready to talk about auditing an icon set where every icon was labelled by default and users now hear everything twice.
Own it as a component-API decision: whether your icon component takes a label prop at all, what it does by default, and how the system prevents double-labelling inside buttons and links. Decide too where inline SVG is worth the markup cost versus serving icons through img.
## Why inline SVG needs different markup When you use `<img src="icon.svg" alt="…">` the image is a single replaced element with a text alternative attribute, and the SVG's internals are invisible to the page. When you inline the SVG — usually to style or animate it with CSS, or to avoid a request — you paste a tree of `<path>`, `<g>` and `<circle>` elements directly into the document. There is no `alt` attribute on `<svg>`. Left unmarked, the result is at best silence and at worst a scattering of unnamed nodes in the accessibility tree. So you have to say explicitly what the SVG is: one image with a name, or nothing at all. ## The meaningful case ```html <svg role="img" aria-label="Download" viewBox="0 0 16 16" width="16" height="16"> <path d="M8 1v9M4 7l4 4 4-4M2 14h12" /> </svg> ``` Two things are doing work: - `role="img"` declares the element an image, which tells assistive technology to treat the subtree as one graphic rather than exposing its children. - `aria-label` supplies the text alternative — the same string you would have put in `alt`. The native alternative is the SVG `<title>` element as the **first child** of `<svg>`: ```html <svg role="img" viewBox="0 0 16 16"> <title>Download</title> <path d="M8 1v9M4 7l4 4 4-4M2 14h12" /> </svg> ``` Note that this `<title>` is the SVG element, not the HTML `title` *attribute* — different things with the same word. It is also rendered as a tooltip on hover by browsers, which some teams want and some do not. Because historical support for picking up the SVG `<title>` has been uneven, `role="img"` with `aria-label` is the recipe most component libraries settle on; supplying both is common and harmless as long as they say the same thing. ## The decorative case Most icons in a real interface are decorative, because they sit beside a visible word that already carries the meaning: ```html <button type="button"> <svg aria-hidden="true" viewBox="0 0 16 16"><path d="…" /></svg> Download </button> ``` `aria-hidden="true"` removes the element and its subtree from the accessibility tree — the SVG equivalent of `alt=""`. The button's name comes from its text content, "Download", and the icon adds nothing to announce. Labelling the icon here would produce "Download Download". ## The icon-only control This is where the question usually goes next, and where most bugs live. An icon-only button needs a name on the **control**, not on the graphic: ```html <button type="button" aria-label="Close dialog"> <svg aria-hidden="true" viewBox="0 0 16 16"><path d="…" /></svg> </button> ``` Putting `role="img"` and a label on the SVG while leaving the button unnamed produces a control announced as "button" with the name coming from wherever it can be scraped — fragile and often wrong. Name the interactive element; hide the decoration inside it. The same reasoning covers an icon that is the only content of a link: the link needs the text, and the icon is decorative. ## Which delivery to choose Inline SVG is the right choice when you need to style parts of the graphic with CSS, animate it, or have it inherit `currentColor`. `<img src="icon.svg" alt="…">` is simpler when you do not: it caches as a separate file, keeps the markup small, and gives you the ordinary `alt` mechanics — including `alt=""` for decoration. Note that an SVG's internal `<title>` is *not* exposed when the file is loaded through `<img>`; the `alt` attribute governs there. ## The defects that ship An inline SVG with no role and no label, announcing as nothing or as stray nodes; a decorative icon labelled so users hear every word twice; an icon-only button whose name lives on the SVG rather than the button; and a label written as the icon's shape ("magnifying glass") instead of its meaning ("Search") — the same purpose-over-appearance rule that governs `alt`.
- If the SVG already has a title element, why do teams still add role="img" and aria-label?Because `role="img"` does a second job: it collapses the SVG subtree into a single image node so its shapes are not exposed individually. And support for picking up the SVG `<title>` has historically varied between browser and screen reader combinations, so `aria-label` is the predictable carrier. When both are present they must say the same thing, or the announced name and the hover tooltip disagree.
- Does an SVG's internal title element do anything when the file is loaded via <img src="icon.svg">?No. Through `<img>` the SVG is an opaque replaced image and its internal markup is not exposed to the accessibility tree — the `alt` attribute is the text alternative, and `alt=""` still marks it decorative. That difference is a reason to keep the alternative text in the consuming HTML rather than inside the asset.
- An icon-only button has aria-label on the svg and nothing on the button. What breaks?The button ends up without a reliable accessible name, so it is announced as an unnamed button and is unusable by name in a screen reader's control list. The fix is to move the label onto the `<button>` — or give the button visible text and visually hide it — and mark the inner SVG `aria-hidden="true"` so nothing inside competes.
saying these in an interview costs you the question
- Expects an alt attribute to work on inline svg
- Labels a decorative icon next to visible text
- Puts the accessible name on the icon instead of the button
- Names the icon by its shape rather than its meaning
- Thinks an svg title element is the same as the title attribute