ICON OOP
Icons & Logos
Guide

How to make icons accessible

An icon either means something or it does not, and that single distinction decides everything about how you mark it up. Get it right and screen reader users understand your interface as well as everyone else. Get it wrong and a button reads as nothing at all.

HomeGuidesAccessible icons

Icons are everywhere in modern interfaces, and most of them are handled badly for accessibility. A search button that is just a magnifying glass reads to a screen reader as an unlabelled button. A status icon that means "error" is invisible to anyone who cannot see the colour red. These are not edge cases; they are the default outcome unless you do something about it.

The good news is that the rules are simple once you see the pattern. Almost every accessibility decision about an icon comes down to one question, asked first.

The one question to ask

Does this icon convey information that is not already in the text next to it? If yes, it needs an accessible name. If no, it is decorative and should be hidden from assistive technology so it adds no noise. Everything else follows from that answer.

The two kinds of icon

Every icon on a page is one of two things, and the markup is completely different for each.

  • Decorative. The icon repeats or decorates something the text already says. A little envelope sitting beside the word "Email", a chevron next to a link, a flourish in a heading. A screen reader should skip it.
  • Meaningful. The icon carries information on its own. An icon-only button, a status indicator, a flag that shows a language, a warning triangle with no words beside it. A screen reader must announce what it means.

The mistake that breaks interfaces is treating a meaningful icon as if it were decorative, usually by accident, because hiding icons is the easy default. The result is a control that works perfectly with a mouse and announces nothing to anyone using a screen reader.

Decorative icons: hide them

If the icon adds nothing a screen reader user would miss, take it out of their experience. How you do that depends on how the icon is placed.

Inline SVG. Add two attributes to the <svg>:

<svg aria-hidden="true" focusable="false" ...>

The first removes it from the accessibility tree, so it is never announced. The second stops older versions of Edge and Internet Explorer from letting users tab onto it.

An <img> tag. Give it an empty alt attribute:

<img src="/star.svg" alt="">

An empty alt is not the same as a missing one. Empty tells the screen reader "skip this, it is decorative". Missing makes the screen reader fall back to reading the file name aloud, which is worse than silence.

A CSS background. Icons set as a background-image are invisible to assistive technology automatically, which is fine for pure decoration, and a reason background icons are a poor choice for anything meaningful.

Meaningful icons: name them

When an icon carries meaning, it needs an accessible name in words. The cleanest approach is a visible text label beside the icon, because it helps everyone, not only screen reader users. Where the design genuinely has no room for text, give the icon a name in markup instead.

Inline SVG with meaning. Tell assistive technology to treat the whole graphic as a single image, then name it:

<svg role="img" aria-label="Verified">
  <path .../>
</svg>

The role="img" matters: without it, some screen readers walk into the SVG and read out its internal shapes instead of treating it as one named image. You can also name it with a <title> as the first child element, which adds a hover tooltip, but support across screen readers is less consistent than aria-label, so prefer the label and add a title only if you want the tooltip too.

A meaningful <img>. Describe what it conveys, not what it looks like:

<img src="/error.svg" alt="Error">

Write the alt text as the information the icon delivers. For a red warning triangle that signals a failed payment, the useful alt is "Payment failed", not "red triangle".

Icon-only buttons and links

This is where most real-world icon problems live. A button or link whose only content is an icon must have an accessible name, or it is announced as just "button" or "link" with nothing to say what it does.

The rule: put the name on the control, and hide the icon inside it. The icon is decorative relative to the button, because the button is what carries the meaning.

<button aria-label="Search">
  <svg aria-hidden="true" focusable="false">...</svg>
</button>

A screen reader announces this as "Search, button", which matches exactly what a sighted user reads from the magnifying glass. The same pattern works for a link: aria-label on the <a>, aria-hidden on the icon. If the button also has visible text, you do not need the label at all; just hide the icon and let the text speak.

A common trap

Do not put the name on both the button and the icon. Labelling the button with aria-label="Search" and also leaving the SVG with a <title>Search</title> can cause the name to be announced twice. Name the control, hide the icon, once each.

Quick reference by delivery method

How the icon is usedDecorativeMeaningful
Inline SVGaria-hidden="true" focusable="false"role="img" + aria-label="..."
<img> tagalt=""alt="meaning"
Icon-only button or linkn/a (the control is meaningful)aria-label on the control, aria-hidden on the icon
CSS backgroundHidden automaticallyAvoid; move it to inline SVG or img so it can be named

If you remember only this table, you will handle the large majority of icons correctly.

Contrast and not relying on colour

Naming an icon helps screen reader users. Two more rules help people with low vision or colour blindness, who can see your interface but not perfectly.

Meaningful icons need contrast. Under WCAG 1.4.11, Non-text Contrast, the meaningful parts of an icon or interface control must reach a contrast ratio of at least 3 to 1 against the colour behind them. A pale grey icon on a white background may look elegant and still fail, leaving it invisible to some users. Decorative icons are exempt, but anything that carries meaning needs to be clearly visible.

Never let colour be the only signal. A red icon for error and a green icon for success look identical to many colour-blind users. Pair the colour with a shape that differs, a cross versus a tick, or with a text label. Colour can reinforce meaning, but it must not be the only thing carrying it.

If you are recolouring icons to hit a contrast ratio or to build a clear status set, the guide to changing icon colour covers doing it cleanly.

Tap targets and focus

An icon button can be perfectly labelled and still be hard to use if it is tiny. Two practical rules:

  • Make the target big enough. Aim for a clickable area of at least 24 by 24 CSS pixels to meet WCAG 2.5.8 at level AA, and 44 by 44 to meet the stricter 2.5.5 at AAA. The visible icon can stay small; add padding around it so the hit area reaches the target size.
  • Keep a visible focus state. Icon buttons must show a clear outline when reached by keyboard. Do not remove the focus ring without replacing it with something equally visible, or keyboard users lose their place.

How to test it

You do not need specialist equipment to catch the common failures. Three quick checks find most problems:

  • Tab through the page. Every icon button and link should receive focus, show a visible outline, and be operable with Enter or Space. If focus skips a control, it is not reachable.
  • Turn on a screen reader. VoiceOver on Mac and iOS, NVDA on Windows, and TalkBack on Android are all free. Move through your icon controls and listen. Each should announce a sensible name and a role, such as "Search, button". "Button" on its own is a fail.
  • Check the contrast. Use any contrast checker on your meaningful icons against their background and confirm they clear 3 to 1.

These three passes, done once, will lift the accessibility of an icon-heavy interface more than any amount of guessing.

Frequently asked questions

Hide it from assistive technology. For an inline SVG, add aria-hidden="true" and focusable="false". For an icon used as an image, give it an empty alt attribute, alt="". A decorative icon sits next to text that already carries the meaning, so announcing it would only add noise.
Put the label on the button, not the icon. Use aria-label on the button, for example a search button becomes button aria-label="Search", and hide the icon inside with aria-hidden="true". A screen reader then announces "Search, button", which is exactly what a sighted user understands from the magnifying glass.
Meaningful icons and the visual parts of interface controls must reach a contrast ratio of at least 3 to 1 against their background, under WCAG 1.4.11 Non-text Contrast. Purely decorative icons are exempt, but if an icon conveys information or is part of a control, it needs to be clearly visible.
It stops the SVG from receiving keyboard focus in older versions of Internet Explorer and Edge, which would otherwise let users tab onto a decorative graphic for no reason. It is harmless in modern browsers and still recommended on inline SVG icons.
For a meaningful inline SVG, add role="img" so it is treated as a single image, then give it a name. aria-label is the most reliable across screen readers. A title element as the first child also works and shows a tooltip on hover, but support is less consistent, so aria-label is the safer default.
Aim for a tap target of at least 24 by 24 CSS pixels to meet WCAG 2.5.8 at level AA, and 44 by 44 to meet the stricter 2.5.5 at AAA. The visible icon can be smaller, as long as the clickable area around it reaches the target size through padding.

Put it into practice: learn the ways to add an SVG icon, recolour icons for contrast, or browse the library to find the icon you need.

Find the right icon for the job

Search 23,000+ icons and logos, recolour them for contrast, and export clean SVG ready to label.

Open the ICON OOP tool