Skip to main content
Back to Blog

Accessible SVG Icons: ARIA, Roles & Screen Reader Best Practices

Learn how to make SVG icons accessible. Understand decorative vs. informative icons, use role='img' with title, aria-hidden for decoration, and aria-label for icon buttons — with tested code patterns.

7 min read
svg
accessibility
aria
screen-reader

Why SVG Icon Accessibility Matters

SVG icons are everywhere — navigation menus, buttons, status indicators, feature lists. But without proper accessibility markup, screen reader users experience one of two problems:

  1. Missing information: The icon conveys meaning (like a warning or a search action), but the screen reader says nothing.
  2. Noise: The icon is purely decorative, but the screen reader announces the raw SVG markup or an unhelpful "image" label.

Both create a frustrating experience. The fix is straightforward once you understand the patterns.

The First Decision: Decorative or Informative?

Before adding any ARIA attributes, ask one question: Does this icon convey information that isn't available in surrounding text?

Decorative icons add visual interest but carry no unique meaning:

  • An icon next to a "Search" label (the label already communicates the action)
  • A decorative divider or background pattern
  • An icon repeating what adjacent text says

Informative icons carry meaning that would be lost without them:

  • A standalone search icon in a button with no visible text
  • A warning icon that indicates an error state
  • A status icon (checkmark, X) showing success or failure

The pattern you use depends entirely on this distinction.

Pattern 1: Decorative Icons — Hide from Screen Readers

When an icon is purely decorative, hide it from assistive technology completely:

<a href="/search">
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
    <path d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 10-.7.7l.27.28v.79l5 4.99L20.49 19l-4.99-5z"/>
  </svg>
  Search
</a>

aria-hidden="true" removes the SVG entirely from the accessibility tree. The screen reader announces "Search, link" — clean, clear, and without redundancy.

Key points:

  • Use aria-hidden="true" whenever visible text already describes the action
  • Do not use role="presentation" — it cancels the native role but doesn't reliably hide content from all screen readers
  • If the SVG is inside a focusable element, add focusable="false" to prevent the icon from receiving tab focus in older browsers (notably IE/early Edge)
<button>
  <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="currentColor">
    <path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/>
  </svg>
  Menu
</button>

Pattern 2: Standalone Informative Icons — role="img" + title

When an icon stands alone and conveys meaning, it needs an accessible name. The most reliable pattern across browser/screen reader combinations:

<svg role="img" aria-labelledby="icon-title" viewBox="0 0 24 24" fill="currentColor">
  <title id="icon-title">Warning</title>
  <path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>
</svg>

Why this pattern works:

  • role="img" tells the browser this is an image (some screen readers skip SVGs without an explicit role)
  • <title> provides the accessible name — it must be the first child element of the <svg>
  • aria-labelledby connects the SVG to its title, ensuring screen readers read it consistently

Adding a Description

For icons that need more context, add a <desc> element:

<svg role="img" aria-labelledby="warn-title warn-desc" viewBox="0 0 24 24" fill="currentColor">
  <title id="warn-title">Connection error</title>
  <desc id="warn-desc">Unable to reach the server. Check your internet connection.</desc>
  <path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>
</svg>

Screen readers announce: "Connection error. Unable to reach the server. Check your internet connection. Image."

When to use <desc>: Only when the icon communicates something complex that a single title can't convey — like a data visualization or a multi-state indicator. For simple icons, <title> alone is sufficient.

Pattern 3: Icon-Only Buttons — aria-label on the Button

The most common scenario: a button that contains only an icon. Place the accessible name on the button, not the SVG:

<button aria-label="Close dialog">
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
    <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
  </svg>
</button>

Why put aria-label on the button, not the SVG?

  • The button is the interactive element — screen reader users navigate by buttons, not by images
  • The SVG is an implementation detail of the button's appearance
  • aria-hidden="true" on the SVG prevents duplicate announcements

Screen readers announce: "Close dialog, button" — exactly what the user needs.

Common Icon Button Examples

<!-- Search button -->
<button aria-label="Search">
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
    <path d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 10-.7.7l.27.28v.79l5 4.99L20.49 19l-4.99-5z"/>
  </svg>
</button>

<!-- Download button -->
<button aria-label="Download file">
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
    <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
  </svg>
</button>

<!-- Delete button -->
<button aria-label="Delete item">
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
    <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
  </svg>
</button>

Pattern 4: Icons with Visible Text — Let the Text Do the Work

When an icon appears alongside visible text that describes the same action, the icon is decorative:

<button>
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
    <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
  </svg>
  Download
</button>

The visible "Download" text serves as both the visual and accessible label. Adding an accessible name to the SVG would cause screen readers to announce "Download image, Download button" — redundant and confusing.

Rule of thumb: If there's visible text, hide the icon. If there's no text, label the icon or its container.

Making AI-Generated Icons Accessible

Icons generated by AI tools (including our AI Icon Generator) come as raw SVG without accessibility attributes. Here's how to add them based on your use case:

For Decorative Use (Icon + Text)

<!-- Generated SVG → Add aria-hidden -->
<a href="/settings">
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
    <!-- AI-generated path data -->
    <path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32..."/>
  </svg>
  Settings
</a>

For Standalone Use (Icon Only)

<!-- Generated SVG → Add role, title, aria-labelledby -->
<svg role="img" aria-labelledby="settings-icon" viewBox="0 0 24 24" fill="currentColor">
  <title id="settings-icon">Settings</title>
  <!-- AI-generated path data -->
  <path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32..."/>
</svg>

For Icon Buttons

<!-- Generated SVG → Wrap in labeled button, hide SVG -->
<button aria-label="Settings">
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
    <!-- AI-generated path data -->
    <path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32..."/>
  </svg>
</button>

Three-Step Workflow

  1. Generate your icon with the AI Icon Generator
  2. Decide if the icon is decorative or informative in your context
  3. Apply the matching pattern from this guide

Combined with the color techniques from our previous post, you get icons that are both theme-ready and accessible.

Quick Reference

ScenarioPatternScreen Reader Announces
Icon + visible textaria-hidden="true" on SVGThe visible text only
Standalone iconrole="img" + <title> + aria-labelledbyThe title text
Icon-only buttonaria-label on button, aria-hidden="true" on SVGThe aria-label + "button"
Complex icon (chart, diagram)role="img" + <title> + <desc> + aria-labelledbyTitle and description
Decorative/ornamentalaria-hidden="true"Nothing (silent)

Testing Your Icons

The best way to verify accessibility is to test with actual screen readers:

  • macOS: VoiceOver (built-in, activate with Cmd + F5)
  • Windows: NVDA (free) or JAWS
  • Mobile: VoiceOver (iOS) or TalkBack (Android)

Quick check: navigate through your page with a screen reader. For each icon, confirm:

  1. Decorative icons are silent
  2. Informative icons announce a meaningful name
  3. Icon buttons announce their action + "button"

Related Tools

  • AI Icon Generator — Generate SVG icons, then apply these accessibility patterns
  • SVG Viewer — Inspect your SVG structure before adding ARIA attributes
  • SVG Optimizer — Clean up SVG markup while preserving accessibility attributes