WCAG fix guide
How to Fix Empty Buttons and Missing Button Names (WCAG 2.2)
Applies to: SC 4.1.2 Name, Role, Value, Level A · SC 2.5.3 Label in Name, Level A · SC 1.1.1 Non-text Content, Level A (image buttons)
Empty buttons appeared on 30.6% of home pages in the WebAIM Million 2026 (detected with WebAIM's WAVE tool). Of WebAIM's six most common error types, it is the only one that has risen every year since 2021, when it stood at 26.9%. WebAIM also counted an average of 4.8 role="button" attributes per home page, up from 3.6 in 2025 (WebAIM). A button with no name is announced as just "button", so screen reader and voice control users can't tell what it does. Search, menu, close, cart, carousel arrows and quantity +/− are the usual culprits.
What counts as a button name
The accessible name is what a screen reader reads out and what a voice control user says to press the button. In order of preference:
- Visible text inside the
<button>: the most robust option, and what sighted users see too. - Visually hidden text inside the button, for icon-only designs.
aria-labeloraria-labelledbypointing at visible text that exists on the page.alttext on an<img>inside the button, orvalueon<input type="submit">.
A title attribute alone is a weak name. The HTML Standard says relying on it "is currently discouraged" because many browsers only show it on mouse hover (HTML Standard).
Common causes and fixes
| Cause | Fix |
|---|---|
Icon font or SVG only (<i class="icon-search">) | Add visually hidden text or aria-label="Search"; add aria-hidden="true" to the icon |
Icon drawn with CSS ::before / ::after | Same as above. The symbol in the stylesheet is not a usable name |
<img> inside the button with empty or missing alt | Give the image alt text that says what the button does (alt="Close") |
<input type="submit" value=""> or <input type="image"> without alt | Add a value ("Subscribe") or alt text |
aria-labelledby pointing at an id that doesn't exist | Fix the id, or use aria-label |
Clickable <div> or <span> | Use a real <button type="button">; it gets keyboard focus and the button role for free |
Visible text "Send" but aria-label="Submit form" | Start the name with the visible words, or drop the aria-label (SC 2.5.3) |
| Menu or accordion toggle | Name it, and add aria-expanded="true/false", updated by your script |
<!-- Icon-only button: hidden text, decorative icon -->
<button type="button" class="cart-toggle" aria-expanded="false" aria-controls="mini-cart">
<svg aria-hidden="true" focusable="false">…</svg>
<span class="visually-hidden">Cart</span>
</button>
<!-- Quantity stepper: name each button with the product -->
<button type="button" aria-label="Decrease quantity for Linen shirt">−</button>
Button or link? If it goes to another URL, use a link. If it does something on the page (opens a menu, submits, closes a dialog), use a <button>. See the link names guide for icon links.
What automated checks flag, and what they don't
In our test of 21 button patterns in headless Chrome with axe-core 4.14.0, the open-source engine many scanners use, with the WCAG A/AA and best-practice rules switched on (October 2026), the results were:
| Pattern | Flagged? |
|---|---|
Empty <button>, icon font or SVG only, CSS-only icon, img with alt="" | Yes (button-name) |
<div role="button"> with no text | Yes (aria-command-name) |
<input type="submit" value=""> / <input type="image"> without alt | Yes |
Visible "Send" with aria-label="Submit form" | Yes (label-content-name-mismatch) |
aria-hidden="true" on a focusable button | Yes (aria-hidden-focus) |
Name from title only | No: passes, but the name is hover-only for many users |
| Only "×" as text | No: passes, but the name is a symbol, not a word like "Close" |
aria-label="button" or "icon" | No: passes, but the name is meaningless |
Menu toggle with no aria-expanded | No: the state isn't checked |
Clickable <div> with no role | No: it isn't in the accessibility tree, so the scanner can't see a button at all |
Who owns the button?
On client sites, the fix route depends on where the button comes from:
- Theme: header search, menu, cart and carousel arrows. Fix once in the template and it applies to every page.
- Plugin or app: sliders, pop-ups, reviews and filters. Check for an update or a label setting, then report it to the developer.
- Third-party widget: chat launchers and cookie banners. These are often in an iframe or script you can't edit, so raise it with the vendor and keep their reply.
- Your own content: custom HTML blocks and embeds. Fix it directly.
CMS-specific steps
- WordPress: In core blocks, the Search block's icon button takes its name from the block's button text, so keep that field filled in even when only the icon shows. The Navigation block's overlay menu button has a built-in name (for example "Open menu"). Check plugin and theme buttons separately. (Checked against Gutenberg source, October 2026.)
- Shopify: In Dawn, the cart, menu, close and quantity buttons get their names from hidden theme text, such as "Decrease quantity for {product}". Don't blank these strings in Online Store › Themes › … › Edit default theme content. Older or custom themes may lack the hidden text; edit the
snippetsor ask the theme developer. - Webflow: For icon-only buttons, add a visually hidden text span, or an
aria-labelcustom attribute (Element settings › Custom attributes). Check in DevTools whether an element styled as a button is really a link or a<button>, and pick the right one for what it does. - Squarespace: Header icons (cart, menu, search) are template-built. Check their names with the DevTools test below, and fix any buttons in Code blocks or injected code yourself. (Squarespace steps unchecked.)
- Wix: Built-in elements have ARIA preset by Wix. For buttons connected to a CMS collection, set the Accessible name connects to field. The Studio Editor's Accessibility panel lets you add only some ARIA attributes to a Text Button, so give it visible text. For custom elements, use Velo's
accessibilityproperties (check support for your element).
Menu names can change between platform versions (steps checked October 2026). If a path doesn't match, check your platform's current help pages.
WordPress, Shopify, Webflow, Squarespace and Wix are trademarks of their respective owners. Glimscope is not affiliated with or endorsed by any of them.
What automated tools can and can't tell you: Automated checkers (including axe-core, which our monitor uses) can flag many instances of this issue, but they cannot judge everything. A human still has to check meaning and context. For scale: Deque reports that in its own sample of first-time audits, its automated tests found 57.38% of issues by volume (Deque report). That is Deque's figure for its sample, not a detection rate for any one tool, and it means a large share of issues still needs manual testing. Scanners catch buttons with no name. They can't tell whether a name like "×" or "button" makes sense, whether a toggle reports its state, or that a clickable
<div>is meant to be a button. Automated tests find only some accessibility issues; manual testing is still required. Not legal advice.
Manual checklist
- In Chrome or Edge DevTools, inspect each icon button and read Name in the Accessibility pane: it should say what the button does
- Tab to every button: each one gets focus and works with Enter and Space
- With a screen reader, menu and accordion toggles announce "expanded" or "collapsed"
- Any visible words on the button appear at the start of its name
- Repeated buttons (quantity, remove, play) say which item they act on
Sources
- www.w3.org/WAI/WCAG22/Understanding/name-role-value.html
- www.w3.org/WAI/WCAG22/Understanding/label-in-name.html
- www.w3.org/WAI/WCAG22/Understanding/non-text-content.html
- webaim.org/projects/million/
- html.spec.whatwg.org/multipage/dom.html#the-title-attribute
- www.deque.com/automated-accessibility-coverage-report/
Check your own site
Run a free automated scan of one page to check it for some issues like this one.
Automated tests find only some accessibility issues; manual testing is still required. Not legal advice.