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 used | Decorative | Meaningful |
|---|---|---|
| Inline SVG | aria-hidden="true" focusable="false" | role="img" + aria-label="..." |
| <img> tag | alt="" | alt="meaning" |
| Icon-only button or link | n/a (the control is meaningful) | aria-label on the control, aria-hidden on the icon |
| CSS background | Hidden automatically | Avoid; 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
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.