SVG Accessibility: How to Make Icons Screen-Reader Friendly

For designers who care about inclusive design · June 2026 · 6 min read

I ran an accessibility audit on a client's marketing site last year. The Lighthouse score was 98. But when I turned on VoiceOver and tabbed through the navigation, every single icon was invisible. Seven SVG icons — home, search, cart, account, menu, close, arrow — all announced as nothing. Just silence between the text links. That's when I realized: almost nobody teaches designers how to make SVGs accessible. Here's what I've learned since.

The Default State of SVG Accessibility (It's Bad)

By default, an SVG element with no accessibility attributes is treated inconsistently by screen readers. Some ignore it entirely. Some announce "image" with no context. Some read the file name if it was loaded via <img>. None of these behaviors are useful. A search icon that announces as "search-icon.svg" is arguably worse than one that says nothing — at least silence doesn't interrupt the flow.

The W3C's SVG Accessibility API Mappings spec defines how SVG should map to platform accessibility APIs, but browser implementation is inconsistent. Relying on defaults means you're probably shipping broken accessibility.

The Three Patterns I Use

After testing across VoiceOver (macOS), NVDA (Windows), and JAWS (Windows), I've settled on three patterns that work reliably. Which one to use depends on what the SVG is doing.

Pattern 1: Decorative SVGs — Hide Them

If the SVG is purely decorative — a background pattern, a divider, an illustration that adds no information — hide it from screen readers entirely:

<svg aria-hidden="true" focusable="false">
  <!-- decorative shapes -->
</svg>

When I use this: Section dividers, background blobs, decorative illustrations, repeated icons that already have a text label right next to them.

Pattern 2: Informative SVGs — Add a Title

If the SVG conveys meaning — a chart, a diagram, an illustration with instructional content — add a <title> element and reference it with aria-labelledby:

<svg aria-labelledby="chart-title" role="img">
  <title id="chart-title">Revenue grew 34% from Q1 to Q4 2025</title>
  <!-- chart paths -->
</svg>

This ensures the screen reader announces "Revenue grew 34% from Q1 to Q4 2025 — image" instead of reading out path coordinates or remaining silent.

Pattern 3: Interactive SVGs — Label the Action

If the SVG is clickable — an icon button, a link — use aria-label on the interactive element, not on the SVG itself:

<button aria-label="Open shopping cart (3 items)">
  <svg aria-hidden="true" focusable="false">
    <!-- cart icon paths -->
  </svg>
  <span class="sr-only">3 items in cart</span>
</button>

I use aria-hidden="true" on the SVG inside a button because the button's aria-label already describes the action. Announcing both would be redundant. The .sr-only text provides a visible-on-focus fallback for users who navigate by keyboard but don't use a screen reader.

What I Test With

I test every icon system I build with three screen readers, in this order:

  1. VoiceOver (built into macOS) — Cmd+F5 to toggle. Free, always available, catches 80% of issues.
  2. NVDA (free, Windows) — Download from nvaccess.org. More widely used than JAWS globally.
  3. Chrome DevTools Accessibility panel — Right-click → Inspect → Accessibility tab. Shows the computed accessible name and role. Not as thorough as a real screen reader but catches missing labels in seconds.

If an icon passes VoiceOver and NVDA, it's probably fine. I don't own JAWS (it costs $95/year), but a client once tested my work with it and reported no issues with these patterns.

Quick Checklist

Need to export accessible SVGs? Use SVG2PNG to convert SVGs to PNG for email clients and legacy apps that don't support inline SVG — and always provide alt text on the resulting <img> tag.

Jamie Park Written by Jamie Park — UI/UX Designer. designing interfaces and design systems for 8 years. Built SVG2PNG after getting tired of client assets on random servers. More about me →