Accessible SVGs
Decorative vs informative SVG icons — aria-hidden, title/desc, role=img, and pairing icons with accessible names on controls.
- accessibility
- accessible-svgs
SVGs are graphics. Accessibility depends on purpose: decorative flourish vs information-carrying icon vs complex chart. Wrong markup either hides meaning or forces screen readers to dump path garbage.
Docs: MDN SVG accessibility, WAI images.
Decorative SVG (most UI icons inside labeled buttons)
<button type="button">
<svg aria-hidden="true" focusable="false" width="16" height="16">
<!-- paths -->
</svg>
Save
</button>
aria-hidden="true" and focusable="false" keep the icon out of the tree; the button text is the name.
Icon-only control
<button type="button" aria-label="Close">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">…</svg>
</button>
Visible text is best when design allows; otherwise aria-label / aria-labelledby.
Informative standalone SVG
<svg role="img" aria-labelledby="logo-title" width="120" height="40">
<title id="logo-title">Frontend Beauty</title>
<!-- graphics -->
</svg>
role="img" + <title> (and optional <desc>) exposes a name.
Linked SVG logo
<a href="/">
<svg role="img" aria-label="Frontend Beauty home">…</svg>
</a>
Or wrap visually hidden text + aria-hidden on the svg.
Complex graphics / charts
- Provide a text alternative: data table, summary, downloadable CSV.
- Don’t rely on color alone for series — do not rely on color alone.
- For interactive charts, keyboard paths and descriptions need product design — often a simplified accessible view.
Inline vs <img src="file.svg">
| Form | Alt approach |
|---|---|
<img src="icon.svg" alt=""> |
Decorative |
<img src="chart.svg" alt="Sales up 12%"> |
Informative |
| Inline SVG | aria-hidden or role="img" + title |
React / icon systems
function Icon({ title, ...props }: { title?: string } & SVGProps<SVGSVGElement>) {
if (!title) {
return <svg aria-hidden focusable="false" {...props} />;
}
return (
<svg role="img" aria-label={title} focusable="false" {...props}>
{props.children}
</svg>
);
}
Default decorative; pass title only when the SVG itself carries meaning.
Footguns
- Focusable SVG inside a button creating extra tab stops (
focusable="false"). - SR reading every
<text>node unintentionally. - Empty
aria-labelon icons. - Using color-only status icons without text.
Interview out-loud answer
“Decorative SVGs get aria-hidden inside named controls. Informative SVGs use role=img and title/aria-label. Icon-only buttons need an accessible name on the button. Charts need a text alternative beyond the graphic.”
Sprites and <use>
SVG sprite systems (<use href="#icon-x">) can orphan titles. Prefer putting the accessible name on the host control (button/link) and marking the svg aria-hidden="true" unless the graphic itself is the content.
Extra practice
Write a minimal demo in a scratch file or the playground: one happy path, one failure path, and one boundary input. If you cannot exhibit a bug that the pattern prevents, you do not own the concept yet — re-read the primary docs linked below and tighten the example until the failure is obvious.
Notes from real codebases
Teams that succeed here keep the rules mechanical: lint where possible, CI for the rest, and a short human checklist for what automation cannot see. Document exceptions with an owner name and a removal date so “temporary” escapes do not become permanent architecture.
Implementation notes
Wire this into real code on the next feature, not only a demo. Prefer the smallest change that encodes the rule — a shared helper, a lint rule, or a checklist item in the PR template. Revisit after a week of production traffic: if users or tests still hit the failure mode, the documentation (and the abstraction) are not sharp enough yet.
Related on this site
- Accessible names computation
- ARIA labels and descriptions
- Do not rely on color alone
- What is the accessibility tree
- WCAG principles POUR
Further reading
Related guides
- Accessible Combobox PatternBuild or evaluate comboboxes with APG keyboard behavior, aria-expanded/activedescendant, and filterable listbox pairing.
- Accessible Forms ErrorsLabel inputs, associate errors with fields, announce failures, and avoid placeholder-only forms that break accessibility.
- Accessible Menus PatternAPG menu and menubar keyboard model — arrow navigation, escape to close, aria-expanded, and when a disclosure is enough.
- Accessible Modals PatternsModal dialogs that work: focus trap, Escape, return focus, aria-modal, and why native dialog or APG patterns beat div soup.
- Accessible Names ComputationHow browsers compute accessible names from content, labels, aria-label, and labelledby — and how that powers Testing Library queries.