Inline SVG is everywhere — chevrons, status dots, social glyphs, the little
magnifier inside a search button. Each one is either decoration, which a
screen reader should skip, or information, which it must convey in words.
The trouble is that a raw <svg> sits in an awkward middle ground:
some browsers expose its child shapes as a meaningless cluster of nodes, others
announce nothing, and a stray <title> or <text>
inside it can leak partial labels. The fix is always to decide which kind of graphic
you have, then make the markup say so explicitly.
This lesson works through the three SVG and icon defects that turn up most often in
audits. Each is a one- or two-attribute change, and each maps to the same root
criterion — 1.1.1 Non-text Content — so once you internalise the
decision, every icon on the page follows the same rule.
What you’ll learn
How to hide a purely decorative SVG from assistive technology with
aria-hidden="true" (and why focusable="false" still
matters); how to give an informative icon a real accessible name with
role="img" and a <title> or
aria-label; and how to make an icon-only link or button announce its
purpose so it isn’t read as an empty control.
Standards this lesson maps to
Standard
Criterion
Level
What it requires
WCAG 2.2
1.1.1 Non-text Content
A
Every non-text element either has a text alternative that serves the same purpose, or — if purely decorative — is hidden from assistive technology.
WCAG 2.2
4.1.2 Name, Role, Value
A
An interactive control built from an icon exposes a name and role to assistive technology.
WCAG 2.2
2.4.4 Link Purpose (In Context)
A
The purpose of each link can be determined from its accessible name — an icon-only link still needs one.
WCAG 2.2
1.4.1 Use of Color
A
Where an icon conveys meaning by colour alone (a status dot), the meaning is also available in text.
EN 301 549
9.1.1.1 (incorporates WCAG)
—
European harmonised standard; references the WCAG A/AA set including non-text content.
Section 508
502.3 / 504 (incorporates WCAG A & AA)
—
US federal ICT must meet WCAG 2.0 Level A and AA, including text alternatives for graphics.
ADA Title II
WCAG 2.1 AA (DOJ rule)
AA
US state/local government web content must conform to WCAG 2.1 AA.
The three problems we’ll fix
Each card below isolates one common SVG or icon defect. For every issue you get a
plain-language statement of the problem, a Bad example (shown as
escaped, non-running code so it can’t affect this page), a Good
example, the copyable Code, and an ordered fix.
Decorative inline SVG not hidden from assistive tech
WCAG 2.2 · 1.1.1AEN 301 549Section 508
A chevron beside a link, a flourish next to a heading,
a glyph that simply repeats the text next to it — these add nothing for a screen
reader user, but a bare <svg> isn’t silent. Depending on the
browser it may expose its <path> and <g>
children as anonymous nodes, announce a stray <title>, or land
in the tab order in older Internet Explorer because SVG is focusable by default
there. The result is noise: extra stops, “graphic” with no name, or a label that
duplicates the adjacent text. Decorative graphics must be removed from the
accessibility tree (1.1.1).
Bad
The icon purely repeats the visible word “Settings”, yet it’s left exposed.
Assistive tech may announce a nameless graphic or, worse, leak its inner
<title>, doubling the label.
The SVG is marked aria-hidden="true" so it’s dropped from the
accessibility tree, and focusable="false" keeps it out of the tab
order. The link’s name comes entirely from the visible text “Settings”.
For a CSS background image or an icon font glyph, the same idea applies: keep
it out of the tree. A background image is already ignored; a pseudo-element
glyph should be hidden with aria-hidden="true" on its host or set
via CSS content with an empty alt equivalent.
decorative-variants.html
<!-- Inline SVG used as decoration -->
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">…</svg>
<!-- <img> used as decoration: empty alt removes it from the tree -->
<img src="divider.svg" alt="">
<!-- Icon-font glyph in a span, hidden from AT -->
<span class="icon-star" aria-hidden="true"></span>
How to fix
Decide the icon is decorative — it adds no meaning the surrounding text
doesn’t already carry.
Add aria-hidden="true" to the <svg> so it’s
removed from the accessibility tree.
Add focusable="false" as well, to keep legacy browsers from
putting the SVG in the tab order.
Remove any <title> from inside a decorative SVG so it
can’t leak a label.
For decorative <img> use alt=""; verify the
graphic no longer appears in the accessibility tree.
Informative icon with no accessible name
WCAG 2.2 · 1.1.1A4.1.2A1.4.1AEN 301 549
Sometimes the icon is the information: a green
tick that means “verified”, a red dot that means “offline”, a warning triangle in a
table cell with no accompanying word. When that meaning lives only in the shape or
the colour, a screen reader user gets nothing — and a user who can’t distinguish
the colour gets nothing either (1.4.1). An informative SVG needs a programmatic
name. Give it role="img" so it’s exposed as a single image, then name
it with a child <title> (referenced via
aria-labelledby for the widest support) or an
aria-label.
Bad
The tick’s meaning, “Verified”, is carried only by its shape and colour. There
is no role and no name, so assistive tech announces nothing useful (1.1.1) and
colour alone carries the status (1.4.1).
The SVG is given role="img" and named by a <title>
through aria-labelledby. It now announces as “Verified, image”, and
the meaning no longer depends on colour.
aria-label is a shorter alternative when no inline title is
wanted. For a status conveyed by colour, the safest pattern is real adjacent
text plus a decorative icon — that satisfies 1.1.1, 4.1.2 and 1.4.1 with no
ARIA at all.
informative-variants.html
<!-- aria-label instead of a child title -->
<svg role="img" aria-label="Verified" focusable="false" viewBox="0 0 24 24">
<path d="m10 16-4-4 1.4-1.4 2.6 2.6 5.6-5.6L17 9l-7 7Z"/>
</svg>
<!-- Best for status: visible text + decorative icon -->
<span class="status">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">…</svg>
Verified
</span>
How to fix
Confirm the icon carries meaning the surrounding text doesn’t — otherwise
treat it as decorative instead.
Add role="img" to the <svg> so it’s exposed
as one image, not a bag of shapes.
Name it with a child <title> referenced by
aria-labelledby, or with aria-label.
Write the name as the meaning (“Verified”, “Offline”), not the picture
(“green tick”).
If the status is shown by colour, also expose it in text so 1.4.1 is met —
often easiest with visible text and a decorative icon.
A magnifier that submits search, a hamburger that opens
the menu, an “×” that closes a dialog — interactive, but with no visible words. If
the only thing inside is an SVG with no name, the control is announced as “button”
or “link” with nothing more, and the user can’t tell what it does (4.1.2, 2.4.4).
The control itself must carry an accessible name. Put the name on the
<button> or <a> — with visually-hidden text or
aria-label — and hide the inner SVG so it can’t compete with or
override that name.
Bad
The button contains only an unnamed icon. Screen readers announce “button”
with no purpose; voice-control users have no label to speak.
The button gets a real name from visually-hidden text, and the icon is hidden
with aria-hidden="true". It announces as “Search, button” and stays
a clean icon visually.
aria-label on the control is an equally valid way to name it, and
works the same on an icon-only link. Keep the inner SVG
aria-hidden="true" either way so a stray title can’t override the
label.
icon-control-variants.html
<!-- Icon-only button named with aria-label -->
<button type="button" aria-label="Close dialog">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M6 6l12 12M18 6L6 18"/>
</svg>
</button>
<!-- Icon-only link named with aria-label (2.4.4) -->
<a href="/cart" aria-label="View cart">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">…</svg>
</a>
How to fix
Put the accessible name on the control itself — the
<button> or <a>, not the SVG.
Use a visually-hidden span (preferred — it survives translation)
or aria-label to supply that name.
Name the action, not the picture: “Search”, “Open menu”, “Close dialog”,
“View cart”.
Mark the inner SVG aria-hidden="true" and
focusable="false" so it doesn’t add a second name or a tab
stop.
Check the rendered control announces as “name + role”, and that its target
is at least 24×24 CSS px (2.5.8).
Recap
Decide first: is the SVG decoration or information? Decoration gets
aria-hidden="true" and focusable="false" so it’s
skipped entirely (1.1.1).
An informative icon needs a real accessible name — role="img" with
a <title> or an aria-label — so its meaning
reaches everyone (1.1.1, 4.1.2).
An icon-only link or button must carry its own text: a
visually-hidden label or aria-label on the control,
with the inner SVG hidden (1.1.1, 2.4.4, 4.1.2).
Never let colour alone carry meaning — pair a status icon with text (1.4.1).
The same fixes satisfy WCAG, EN 301 549, Section 508, and ADA
Title II at once — classify each graphic correctly and you meet them all.