Icons Accessibility for Icon-Only Buttons
Icon-only buttons look clean, but without an accessible name they are invisible to screen reader users, so here is how to label them correctly and avoid announcing decorative icons twice.
The Problem with Icon-Only Buttons
A magnifying-glass icon reads as "search" at a glance, and an X reads as "close", but only if you can see it. Screen readers don't interpret the shape of an SVG path or an icon-font glyph; they announce whatever accessible name is attached to the element. When a button contains only an icon and no text, and that icon carries no label, the button has no name at all. A screen reader user tabbing through the page hears nothing more useful than "button", with no clue what pressing it will do.
- A close button showing only an X icon
- A search button showing only a magnifying glass
- A hamburger menu button showing only three lines
- A trash-can icon used to delete a row in a table
Example
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!-- This button has no accessible name -->
<button class="icon-btn">
<svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
<path d="M18 6 6 18M6 6l12 12" stroke="currentColor" stroke-width="2" fill="none"/>
</svg>
</button>
<style>
.icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border: none;
border-radius: 6px;
background: #f1f1f1;
cursor: pointer;
}
</style>
</body>
</html>Giving the Button an Accessible Name
Example
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!-- Option A: aria-label directly on the button -->
<button class="icon-btn" aria-label="Close">
<svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
<path d="M18 6 6 18M6 6l12 12" stroke="currentColor" stroke-width="2" fill="none"/>
</svg>
</button>
<!-- Option B: visually hidden text, kept in the DOM for assistive tech -->
<button class="icon-btn">
<svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
<path d="M18 6 6 18M6 6l12 12" stroke="currentColor" stroke-width="2" fill="none"/>
</svg>
<span class="visually-hidden">Close</span>
</button>
<style>
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
</style>
</body>
</html>Decorative Icons Beside Visible Text
Not every icon needs a label. When a button already shows visible text, like a "Delete" button with a trash-can icon next to the word, the icon is purely decorative. The text already gives screen reader users everything they need, so the icon should not be announced too. Add aria-hidden="true" to the icon in that case. Without it, some screen readers announce the icon's role or an embedded title, so users hear something like "trash icon, Delete, button" instead of the clean "Delete, button".
Example
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!-- The icon is decorative here, the word "Delete" is the accessible name -->
<button class="text-icon-btn">
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" focusable="false">
<path d="M4 7h16M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2m-9 0 1 12a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1l1-12"
stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>
</svg>
Delete
</button>
</body>
</html>Exercise: Icons Accessibility
A decorative icon sits right next to visible text that already reads "Delete". What should be done for screen reader users?