Empty buttons: how to fix icon-only buttons
Updated 2026-10-24 · Altlark guides
An empty button is a button with no accessible name. It usually looks fine on screen: a hamburger menu icon, an X to close a popup, a magnifying glass, carousel arrows. But in the HTML there's no text, so a screen reader announces "button" and nothing else. The user has to press it to find out what it does, and a voice-control user can't target it by name at all.
Which WCAG criterion applies
- 4.1.2 Name, Role, Value, Level A: for all user interface components, the name and role can be programmatically determined. A button's role is clear; its name is missing.
Bad vs fixed: hamburger menu
<button class="menu-toggle">
<span class="bar"></span><span class="bar"></span><span class="bar"></span>
</button><button class="menu-toggle" aria-label="Menu" aria-expanded="false" aria-controls="main-nav">
<span class="bar" aria-hidden="true"></span><span class="bar" aria-hidden="true"></span><span class="bar" aria-hidden="true"></span>
</button>aria-expanded (updated by your script when the menu opens) tells screen-reader users whether the menu is open. It isn't part of the empty-button check, but it's the natural next fix for the same element.
Bad vs fixed: close button on a popup
<button class="modal-close"><i class="icon-x"></i></button>
<button class="modal-close">×</button>The first has no text at all. The second is technically named "×", which many screen readers read as "times" or "multiplication sign". Name it in words:
<button class="modal-close" aria-label="Close"><i class="icon-x" aria-hidden="true"></i></button>Bad vs fixed: carousel arrows
<button class="slick-prev"></button>
<button class="slick-next"></button><button class="slick-prev" aria-label="Previous slide"></button>
<button class="slick-next" aria-label="Next slide"></button>If the carousel moves on its own, it also needs a pause control. See autoplay media for the related timing rules.
Bad vs fixed: visible text is best
Where the design allows, visible text beats a hidden name, because everyone benefits:
<button type="submit">
<svg aria-hidden="true" focusable="false">...</svg>
Search
</button>Bad vs fixed: input buttons and image buttons
<input type="button" class="btn-go">
<input type="image" src="go.png"><input type="button" class="btn-go" value="Apply filters">
<input type="image" src="go.png" alt="Search">For type="submit" and type="reset", browsers supply a default label ("Submit", "Reset") when there's no value, so Altlark doesn't flag them. A specific value like "Send message" is still clearer.
Don't fake buttons with divs
<div class="btn" onclick="openCart()"><i class="icon-cart"></i></div>A <div> with a click handler isn't reachable by keyboard and isn't announced as a button. Use a real button:
<button type="button" onclick="openCart()" aria-label="Open cart"><i class="icon-cart" aria-hidden="true"></i></button>If you really can't change the element, it needs role="button", tabindex="0", a name, and key handlers for Enter and Space. Altlark checks elements with role="button" for a name too, but it can't check the keyboard behavior; you need to test that by tabbing to it.
What Altlark checks exactly
Altlark checks every <button>, every element with role="button", <input type="button"> and <input type="image"> that isn't hidden from assistive technology. A button has a name if it has any of: a non-empty aria-label, aria-labelledby or title; text inside (ignoring children with aria-hidden); an image with alt text inside; an SVG title inside. For type="button" inputs it also accepts a non-empty value, and for image inputs a non-empty alt. Buttons with none of these are reported as "Empty button" with the selector and an HTML snippet.
Limits
The check confirms a name exists, not that it's right. A button named "button" or "icon" passes but doesn't help. Also, many chat widgets, cookie banners and booking tools inject their buttons with JavaScript. Altlark reads server HTML and won't see those; tab through them yourself or ask the vendor for their accessibility documentation.
Testing it yourself
In Chrome or Firefox, right-click the button and choose Inspect, then look at the Accessibility pane: the computed "Name" is what assistive technology announces. An empty name confirms the issue. Then try the page with a screen reader. On a Mac, VoiceOver is built in (Cmd+F5); on Windows, NVDA is free. Press Tab to move between controls and listen. Every button should be announced as "[name], button", and toggles like a menu should also say whether they're expanded or collapsed. Finally, check that each button works with the keyboard: Enter and Space should both activate a real <button>, and focus should go somewhere sensible afterwards (into an opened menu or dialog, and back to the button when it closes).
Naming conventions that work
Use a verb or a clear noun: "Close", "Search", "Open menu", "Add to cart", "Remove item: blue mug". When several buttons do the same kind of action on different things, include the thing, so a list of "Remove" buttons in a cart becomes distinguishable. Keep names short; screen-reader users hear them every time they move past. And don't include the word "button" in the name, because the role is already announced.
Checklist
- Run the free scan on a page with your header, any popup and any carousel.
- Name every icon-only button with aria-label, in words that describe the action ("Close", "Open menu", "Next slide").
- Hide the decorative icon with
aria-hidden="true". - Replace clickable divs with real buttons.
- Re-scan, then try every button with the keyboard (Tab to reach, Enter or Space to press).