SVG images need alternative text
- Rule:
axe/svg-img-alt - Checks: <svg> elements with an img or image role must have alternative text
- WCAG: 1.1.1
- Fix class:
content: A fix needs authored text.
Who it affects
Section titled “Who it affects”- People who use a screen reader or a braille display, most of them blind.
How to fix it
Section titled “How to fix it”An <svg role="img"> conveys information but has no name
Section titled “An <svg role="img"> conveys information but has no name”Add a <title> directly inside the <svg>, before its shapes, and point the <svg>’s aria-labelledby at it, or name it with aria-label. Decide the words from what the graphic conveys in its context.
<svg role="img" viewBox="0 0 24 24" aria-labelledby="paid-title"> <title id="paid-title">Payment received</title> <path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"></path></svg>The SVG is decorative, or text beside it says the same
Section titled “The SVG is decorative, or text beside it says the same”Remove role="img" and add aria-hidden="true", so assistive technology skips it.
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24"><path d="M12 2 2 22h20z"></path></svg>The SVG is a chart or diagram
Section titled “The SVG is a chart or diagram”Give it a short name that says what it shows, and put the full information, such as the data, in text or a table beside it.
Fixes that fail
Section titled “Fixes that fail”Nesting the <title> inside a <g> or a shape
Section titled “Nesting the <title> inside a <g> or a shape”A <title> names its parent, so it names that part rather than the <svg>, and the image stays unnamed.
Adding only a <desc>
Section titled “Adding only a <desc>”A <desc> gives a description, not a name, so the image stays unnamed and axe still reports it.
Keeping a <title> a design tool exported, such as “Layer 1” or “icon-check-24”
Section titled “Keeping a <title> a design tool exported, such as “Layer 1” or “icon-check-24””axe accepts any text, but people hear words that mean nothing to them. Replace it with what the graphic conveys.
In React
Section titled “In React”The part of the fix that differs in React, in its syntax. The rest of the guidance holds.
An SVG component gives its <title> a hard-coded id
Section titled “An SVG component gives its <title> a hard-coded id”Build the id with useId, so each instance’s aria-labelledby points at its own <title>.
function StatusIcon({ label }) { const titleId = useId(); return ( <svg role="img" viewBox="0 0 24 24" aria-labelledby={titleId}> <title id={titleId}>{label}</title> <path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z" /> </svg> );}An icon component always sets role="img", named or not
Section titled “An icon component always sets role="img", named or not”Have callers say when an icon is decorative, and render aria-hidden="true" only then. Otherwise keep role="img" with the label they pass, so an icon left unnamed still shows up in axe instead of being hidden.
function Icon({ label, decorative = false, children }) { return decorative ? ( <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24"> {children} </svg> ) : ( <svg role="img" aria-label={label} viewBox="0 0 24 24"> {children} </svg> );}Fixes that fail in React
Section titled “Fixes that fail in React”Hiding every icon that has no label with aria-hidden="true"
Section titled “Hiding every icon that has no label with aria-hidden="true"”A missing name does not make an icon decorative. It silences axe, and screen reader users lose meaningful icons, such as a status or a warning.
Generating the <title>’s id with Math.random()
Section titled “Generating the <title>’s id with Math.random()”It differs between the server and the client render, so hydration reports a mismatch. useId is unique and stable.
More on the rule
Section titled “More on the rule”axe-core’s documentation of the rule
CORA’s fix guidance adapts content from accessibility-agents, under the MIT License: see its notice.