Skip to Content
Component ExamplesIcons

Overview

Icons are everywhere in modern interfaces — navigation, buttons, status indicators, social links. The critical accessibility question is always the same: is the icon decorative (it appears next to text that already conveys the meaning) or informative (it is the only way the meaning is communicated)? Getting this wrong in either direction causes problems. A decorative icon without aria-hidden="true" may cause screen readers to announce the SVG’s title, path data, or Unicode codepoint. An informative icon without an accessible name leaves a button or link completely unlabeled. SVGs are preferred over icon fonts because they are real DOM elements that can be properly hidden with aria-hidden, while icon fonts rely on CSS pseudo-elements and Unicode Private Use Area codepoints that screen readers may attempt to read.

WCAG Criteria:

Key requirements:

  • Decorative icons (next to visible text) must be hidden with aria-hidden="true" so screen readers skip them
  • Add focusable="false" on SVGs to prevent a legacy IE/Edge bug where SVGs receive keyboard focus
  • Informative icon-only buttons must have an accessible name via aria-label on the button (not on the SVG)
  • Never put role="img" and a <title> on a decorative SVG — this adds redundant announcements
  • SVGs are preferred over icon fonts because icon font glyphs in the Unicode Private Use Area may be announced as random characters
  • If using icon fonts, set aria-hidden="true" on the <i> or <span> element and provide the accessible name on the parent

Decorative Icon

Exposed Decorative SVG vs. Properly Hidden Decorative SVG

Inaccessible
<!-- SVG has no aria-hidden — screen reader may read icon content --> <button> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path> <polyline points="9 22 9 12 15 12 15 22"></polyline> </svg> Home </button>
Live Preview

Screen reader may announce: "graphic, Home" or SVG path data before "Home"

Accessible
<!-- aria-hidden + focusable="false" hides the decorative icon --> <button> <svg aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path> <polyline points="9 22 9 12 15 12 15 22"></polyline> </svg> Home </button>
Live Preview

Screen reader announces: "Home, button" — icon is hidden

What’s wrong with the exposed decorative SVG?

  • Without aria-hidden="true", screen readers may try to announce the SVG — depending on the browser and screen reader combination, users may hear “graphic”, the SVG’s <title> if present, or even path data
  • The icon is purely decorative because the text “Home” already conveys the button’s purpose — the SVG adds no information
  • Without focusable="false", Internet Explorer and older Edge versions allow SVGs to receive keyboard focus, creating an extra (meaningless) tab stop
  • The result is a degraded experience: “graphic, Home, button” instead of the clean “Home, button”

What the screen reader announces:

VersionAnnouncement
Inaccessible (SVG exposed)“graphic, Home, button” or “img, Home, button” (varies by screen reader)
Accessible (SVG hidden)“Home, button”

Informative Icon Button

Unlabeled Icon Button vs. Labeled Icon Button

Inaccessible
<!-- Icon-only button with no accessible name --> <button> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <line x1="18" y1="6" x2="6" y2="18"></line> <line x1="6" y1="6" x2="18" y2="18"></line> </svg> </button> <!-- Screen reader says: "button" — what does it do? -->
Live Preview
Dialog Title

Screen reader announces: "button" — no accessible name

Accessible
<!-- aria-label on the button provides the accessible name --> <button aria-label="Close"> <svg aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <line x1="18" y1="6" x2="6" y2="18"></line> <line x1="6" y1="6" x2="18" y2="18"></line> </svg> </button> <!-- Screen reader says: "Close, button" -->
Live Preview
Dialog Title

Screen reader announces: "Close, button"

What’s wrong with the unlabeled icon button?

  • The button contains only an SVG with no text content — its computed accessible name is empty
  • Screen readers announce “button” with no indication of what the button does
  • This is a WCAG 4.1.2 failure: every interactive element must have an accessible name
  • Adding aria-label to the SVG instead of the button would be incorrect — the name should be on the interactive element, not its child

What the screen reader announces:

VersionAnnouncement
Inaccessible (no name)“button” (no indication of purpose)
Accessible (aria-label)“Close, button”

Where to put the accessible name:

ScenarioTechnique
Icon next to visible textaria-hidden="true" on the icon — button already has a name from the text
Icon-only buttonaria-label on the <button> — SVG still gets aria-hidden="true"
Icon-only linkaria-label on the <a> — SVG still gets aria-hidden="true"
Standalone informative imagerole="img" + aria-label on the SVG (rare — used for infographics, not UI icons)

Key Teaching Points

TechniquePurposeWhen to use
aria-hidden="true" on SVGHide decorative icon from screen readersAlways — whether the icon is decorative or inside a labeled button
focusable="false" on SVGPrevent IE/Edge focus bugAlways, alongside aria-hidden="true"
aria-label on buttonProvide accessible name for icon-only buttonsWhen there is no visible text inside the button
Visible text in buttonProvides accessible name naturallyPreferred over aria-label when space allows
SVGs over icon fontsReal DOM elements, proper ARIA supportAlways — icon fonts use Private Use Area codepoints that screen readers may read

The decision tree:

  1. Does the icon appear next to text that conveys the same meaning? Yes — it is decorative. Add aria-hidden="true" focusable="false" to the SVG. Done.
  2. Is the icon the only content in an interactive element (button, link)? Yes — it is informative. Add aria-label to the button/link, and aria-hidden="true" focusable="false" to the SVG.
  3. Is the icon a standalone image conveying information (e.g., a status indicator)? Yes — add role="img" and aria-label to the SVG itself.

Resources