usability.cat
Issue Wiki

Decorative SVG Issues

Your decorative icons and graphics are being narrated by screen readers like unnecessary commentary. Here's how to silence them.

What is this?

Imagine watching a movie and the narrator describes every detail of the wallpaper pattern in every scene. "The wall has a repeating floral motif in dusty rose with gold accents." You did not ask for that. You just want to follow the plot. That is what happens when decorative SVGs (icons, flourishes, background graphics) are not properly hidden from screen readers. They get announced, adding noise and confusion for visitors who are trying to navigate your actual content.

Decorative images are visuals that add aesthetic value but no information. Think: divider lines, background patterns, icons next to text that already explains the meaning.

Why it matters

  • For your visitors: Screen reader users hear every SVG that is not properly hidden. An icon next to the word "Settings" might be announced as "image, settings" — doubling the information. A decorative wave divider might be read as "group" or "image" with no description. Multiply this across a full page and the experience becomes cluttered and disorienting.
  • For your business: Excessive screen reader noise makes your site feel unprofessional and hard to use. Visitors will leave for competitors whose sites are cleaner to navigate.
  • The standard: WCAG 1.1.1 (Non-text Content) specifies that purely decorative images should be implemented so assistive technology can ignore them. Decorative content should be invisible to screen readers.
Decorative SVG properly hidden
<!-- Decorative icon next to text — hide it -->
<button>
  <svg aria-hidden="true" focusable="false">
    <path d="M12 2L2 7l10 5 10-5-10-5z" />
  </svg>
  Settings
</button>

<!-- Decorative divider — hide it -->
<svg aria-hidden="true" focusable="false" class="divider">
  <line x1="0" y1="0" x2="100%" y2="0" />
</svg>
Decorative SVG exposed to screen readers
<!-- Screen reader announces: "image, settings" or "group, settings" -->
<button>
  <svg>
    <path d="M12 2L2 7l10 5 10-5-10-5z" />
  </svg>
  Settings
</button>

<!-- Screen reader announces: "image" or "group" (confusing) -->
<svg class="divider">
  <line x1="0" y1="0" x2="100%" y2="0" />
</svg>

How to fix it

React / Next.js

When using icon libraries like Lucide React, icons typically need aria-hidden when accompanied by text.

// src/components/nav-link.tsx
import { Settings, Home, Bell } from "lucide-react";

export function NavLinks() {
  return (
    <nav aria-label="Main navigation">
      {/* Icons are decorative here — the text does the talking */}
      <a href="/" className="flex items-center gap-2">
        <Home className="h-4 w-4" aria-hidden="true" />
        <span>Home</span>
      </a>

      <a href="/settings" className="flex items-center gap-2">
        <Settings className="h-4 w-4" aria-hidden="true" />
        <span>Settings</span>
      </a>

      {/* Icon-ONLY button: NOT decorative — needs a label instead */}
      <button aria-label="Notifications">
        <Bell className="h-5 w-5" aria-hidden="true" />
      </button>
    </nav>
  );
}

// Decorative background SVG
export function WaveDivider() {
  return (
    <svg
      aria-hidden="true"
      focusable="false"
      className="w-full text-neutral-800"
      viewBox="0 0 1440 60"
      preserveAspectRatio="none"
    >
      <path
        d="M0,30 C360,60 720,0 1080,30 C1260,45 1350,30 1440,30 L1440,60 L0,60 Z"
        fill="currentColor"
      />
    </svg>
  );
}

Plain HTML

<!-- DECORATIVE: icon next to text — hide the icon -->
<a href="/profile">
  <svg aria-hidden="true" focusable="false" width="16" height="16">
    <circle cx="8" cy="8" r="7" />
  </svg>
  My Profile
</a>

<!-- DECORATIVE: background shape — hide it completely -->
<svg aria-hidden="true" focusable="false" class="bg-wave">
  <path d="..." />
</svg>

<!-- MEANINGFUL: standalone icon conveying information — give it a label -->
<svg role="img" aria-label="Warning: service disruption">
  <title>Warning: service disruption</title>
  <path d="..." />
</svg>

<!-- MEANINGFUL: logo — give it alt text equivalent -->
<svg role="img" aria-label="Acme Corp logo">
  <title>Acme Corp logo</title>
  <path d="..." />
</svg>

The decision tree is simple:

  1. Is the SVG purely decorative (dividers, patterns, icons next to text)? Add aria-hidden="true" and focusable="false"
  2. Does the SVG convey meaning on its own (warning icon, logo, chart)? Add role="img" and either aria-label or a <title> element inside the SVG
  3. Is the SVG an icon inside a button with no text? Hide the SVG, label the button

The focusable="false" attribute prevents Internet Explorer and older Edge from adding SVGs to the tab order, which could confuse keyboard users.

Medium impactaccessibility~1 paw

Decorative SVGs are not the biggest accessibility problem, but they add up. A page with 20 unhandled icons becomes a noisy mess for screen reader users. The cat expects clean, intentional markup.

How the cat scores this

The cat identifies all SVG elements on the page and classifies them as decorative or meaningful based on context. Decorative SVGs (those adjacent to descriptive text, used as backgrounds, or used as visual dividers) are checked for aria-hidden="true". Meaningful SVGs (standalone icons conveying information) are checked for accessible names via role="img" with aria-label, aria-labelledby, or a <title> element. SVGs that are neither hidden nor labeled get flagged.

Further reading

On this page