Your Icon Buttons Have No Name, and the Screen Reader Says So

November 13, 2026

A button whose only content is an SVG icon has no text for the browser to use as its accessible name, so a screen reader announces bare button and the user has to guess. Name the button with aria-label, and hide the decorative icon with aria-hidden.

The name is computed, not written

Every control on a page has an accessible name, whether the author wrote one or not. The browser computes it by walking a fixed priority chain: aria-labelledby first, then aria-label, then an associated label element, then the visible text inside the control, then the title attribute as a last resort. Whichever source comes first wins, and everything below it is ignored. An icon-only button has no visible text, no label, and usually no aria-label, so the chain runs out and the name comes back empty. The role survives, because a native button is a button to every screen reader without any extra markup. The name does not, and a role without a name is a mystery control.

This is the single most common missing-name failure on a storefront, and it clusters in exactly the places owners never look: the close button on the cart drawer, the search icon in the header, the wishlist heart on every product card, the quantity stepper plus and minus. Each one is a control a keyboard user will reach, and each one announces as button, button, button, with nothing to tell them apart.

The five places the name comes from

Start with visible text whenever it exists. A button that reads Add to cart already has its name, and nothing else is needed. For form fields, a real label element tied with for and id is the correct source, and it beats every ARIA option on reliability and translation. When there is genuinely no visible text, aria-label supplies the name directly, which is the right tool for an icon-only search field or a close button on a modal. aria-labelledby points at other visible text on the page and concatenates it, which fits cases like a delete button next to a product name. The title attribute sits at the bottom of the chain and should never be the plan; some screen readers ignore it entirely.

The order matters because a higher source overrides a lower one. An aria-label on a button with visible text replaces the visible text as the name, which is how a button that reads Buy now ends up announcing cta_primary_1. A blank aria-label is worse: it overrides the label below it with nothing. The chain is strict, and the mistakes it produces are silent until a screen reader user hits them.

The two mistakes that break voice control

The first mistake is the name that does not contain the visible label. WCAG 2.5.3, Label in Name, requires the accessible name to include the visible text, because voice-control users speak what they see. A button that shows Checkout and announces Proceed to payment cannot be activated by voice. The fix is to make the two match, not to add more ARIA. The second mistake is naming the icon instead of the button. An aria-label on the SVG does nothing for the button, and an aria-hidden missing from the SVG means the screen reader announces the icon title on top of the button name. Hide the decoration, name the control.

Both mistakes survive every automated scan, because the scanner can see that a name exists and cannot judge whether it is the right name. That is why the test has to be done by ear: turn on a screen reader, tab through the header and the cart, and write down what each control actually announces. The list of bare buttons is usually longer than anyone expects, and every one of them is a five-minute fix.

The one-minute audit

Open the storefront, tab to the header, and count the controls that announce only their role. Then do the same in the cart drawer and on a product page, where the stepper and the wishlist live. For each bare button, decide whether it needs visible text or an aria-label, and write the name as the action it performs: Close cart, Search products, Remove item, Increase quantity. Specific verbs, not generic ones. A button named Delete item is usable; a button named Button is not. Ship the names with the next deploy, and add the screen-reader pass to the release checklist, because new icon buttons arrive with every theme update and every app install.

Frequently asked questions

Does a button with visible text need aria-label too?

No. The visible text is the accessible name, and adding aria-label would override it. Only reach for aria-label when there is no visible text to use, which is the case for icon-only controls.

Why not use the title attribute as the name?

Because it sits at the bottom of the priority chain and some screen readers ignore it. It also only appears on hover for sighted users, so it helps nobody reliably. Use a label element or aria-label instead.

Should the aria-label sit on the button or the icon inside it?

On the button. The button is the control, and it is the control that needs the name. Mark the SVG icon aria-hidden so it does not add its own announcement on top.

How is this different from the placeholder problem?

A placeholder is not a name either, but it fails differently: it disappears when the user types, and it is ignored by the name computation for most controls. Both leave a control unnamed; the placeholder at least shows something on screen first.