Quick answer: This audit fails when a button has no text a screen reader can announce, usually an icon-only close, menu, search or play button. Fix it by adding an aria-label to the button or visually hidden text inside it, and mark the icon aria-hidden. Screen readers otherwise announce it as just "button".
This Lighthouse audit fails when a <button> on the page has no text a screen reader can announce. The usual cause is an icon-only button: a close ×, a hamburger menu, a search magnifier, a carousel arrow, a video play button. Sighted users see the icon. A screen reader reaches the button and says "button", which tells the user nothing about what it does.
TL;DR
- What: One or more
<button>elements have no accessible name. - Why it matters: Screen readers announce these as just "button", and voice control users have nothing to say to press them.
- Fix: Give every button visible text, an
aria-label, or visually hidden text. Hide the decorative icon witharia-hidden="true".
What does the button-name audit check?
Lighthouse runs the axe-core rule button-name against the rendered DOM. Deque's own documentation titles the same rule "Buttons must have discernible text", so you will see both wordings in search results and in axe DevTools. They are the same check.
It computes the accessible name of each native <button> element, and fails if that name is empty. The name comes from the first of these that produces text:
aria-labelledbypointing at another elementaria-labelon the button- The text content of the button, including
alttext of any image inside it titleon the button
If all four are empty, the audit fails. The passing title reads "Buttons have an accessible name"; the failing one is "Buttons do not have an accessible name".
Two sibling audits cover the other button shapes, so a button can fail under a different id:
<input type="button">,type="submit"andtype="reset"are checked byinput-button-name, which reads thevalueattribute.- A
<div>or<span>withrole="button"is checked byaria-command-name.
What does "Element does not have inner text that is visible to screen readers" mean?
When you expand a failing button in the Lighthouse report, each offender carries this block of text from axe-core:
Fix any of the following:
Element does not have inner text that is visible to screen readers
aria-label attribute does not exist or is empty
aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty
Element has no title attribute
Each line is one way the button could have got a name, and each one was checked and came up empty. "Fix any of the following" is literal: satisfying one line passes the audit. The first line means the button has no text content at all, or its only content is an icon, an SVG, or text hidden with display: none. The same block appears under the link-name audit for anchors, which is why the phrase is so widely searched on its own.
Why do buttons without an accessible name matter?
Buttons are where the page does things: open the menu, add to cart, close the dialog, submit the form. A nameless button is an action the user cannot identify.
- Screen readers announce "button" with no purpose. On a page with six icon buttons in the header, the user hears "button, button, button" and has to guess.
- Voice control users say "click Close" or "click Menu". With no name there is nothing to say, and they fall back to numbered overlays.
- WCAG conformance. This is a failure of SC 4.1.2 Name, Role, Value at Level A, the minimum level most accessibility laws reference.
- Lighthouse score.
button-namecarries a weight of 10 in the accessibility category in Lighthouse 13.5, the top tier, shared by only nine audits.link-nameweighs 7. The audit is pass or fail for the whole page, so a single unlabeled close button costs the full 10.
How do I fix "buttons do not have an accessible name"?
Pick whichever of these fits the markup. All four produce a valid accessible name.
<!-- FAILS: icon-only button, nothing to announce -->
<button class="menu-toggle"><svg>...</svg></button>
<!-- FIX 1: aria-label on the button. Best for icon-only buttons. -->
<button class="menu-toggle" aria-label="Open menu">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
<!-- FIX 2: visually hidden text. Works without ARIA and survives page translation. -->
<button class="menu-toggle">
<svg aria-hidden="true" focusable="false">...</svg>
<span class="sr-only">Open menu</span>
</button>
<!-- FIX 3: alt text, when the button wraps an <img> -->
<button><img src="/icons/search.svg" alt="Search"></button>
<!-- FIX 4: real visible text, always the best option when you have room -->
<button>Add to cart</button>
The sr-only class, if your CSS framework does not already ship one (Tailwind calls it sr-only, Bootstrap 5 calls it visually-hidden):
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
Put aria-hidden="true" on the icon in fixes 1 and 2. Without it, some screen readers announce the SVG's own title or an icon font's glyph alongside your label. Hide the graphic and let the label speak.
Name the action, not the icon. "Close dialog", not "X". "Next slide", not "Right arrow". For a toggle, keep the name stable and expose state with aria-expanded or aria-pressed rather than swapping the label between "Open menu" and "Close menu".
What are the most common causes on a real site?
In a scan of 269 production storefronts, button-name failed on 22.7% of them (61 sites). Re-running live on failing stores, the offenders were the same few shapes every time:
- Icon-only utility buttons built with utility classes. A Tailwind
<button class="rounded-lg bg-transparent flex h-[30px] w-[28px] ...">holding only an SVG, repeated for every wishlist heart or quantity control in a product grid. - Video play buttons.
<button class="video-play-btn" type="button">with the triangle drawn in CSS or as a background image, so the element has no content at all. - Carousel and slider controls. Previous and next arrows, and especially the pagination dots, which are usually empty
<button>elements styled as circles. - Modal and drawer close buttons. An × drawn with an SVG or an icon font.
- Header icons. Search, account, cart and hamburger buttons that only show an icon on mobile, where the visible label is hidden with
display: noneat small breakpoints. - Quantity steppers. The − and + buttons beside a quantity input.
How do I fix this in React, Next.js, WordPress, or Shopify?
React / Next.js
Icon components usually render an <svg>, so the name goes on the <button>, not the icon:
// FAILS
<button onClick={close}><XIcon /></button>
// FIXED
<button onClick={close} aria-label="Close dialog">
<XIcon aria-hidden="true" />
</button>
If you build a shared IconButton component, make label a required prop and set aria-label from it, so a nameless icon button cannot compile. Libraries such as Radix and MUI already require or warn about a label on their icon buttons.
For carousel dots, name each one by position: aria-label={Go to slide ${i + 1}}. Catch the rest in CI with eslint-plugin-jsx-a11y for static markup, and @axe-core/react or Playwright with @axe-core/playwright for rendered output, since icon components hide the problem from linting.
WordPress
- Theme header toggles. The mobile menu and search toggles are the most common offenders. Check the rendered
<button>in DevTools; many themes ship ascreen-reader-textspan you can fill in the Customizer or template. - Page builders. Elementor, Divi and similar builders let you drop an icon widget linked to an action with no label field filled in. Look for the widget's "Accessible name" or "ARIA label" setting.
- Slider plugins. Arrows and dots from older slider plugins are frequently empty buttons. Update the plugin, or switch to one that labels its controls.
- Hidden labels. WordPress core's
screen-reader-textclass clips text correctly. Do not replace it withdisplay: none.
Shopify
The usual culprits live in the header, cart drawer and product sections:
<!-- FAILS -->
<button type="button" class="drawer__close">{% render 'icon-close' %}</button>
<!-- FIXED -->
<button type="button" class="drawer__close" aria-label="{{ 'accessibility.close' | t }}">
{% render 'icon-close' %}
</button>
Use a translation key rather than a hardcoded string so the label follows the storefront locale. Dawn-based themes label their close, quantity and slider buttons already; older and heavily customised themes, and buttons injected by apps, frequently do not. If the offender comes from an app, the fix belongs to the app developer, so report it to them.
What button-name pitfalls should I avoid?
- Do not use
titleas your fix. It passes the audit, buttitleis not shown on touch devices, is inconsistently announced, and does not help voice control users. It passes the test without helping anyone. - Do not hide the label with
display: noneorvisibility: hidden. Both remove the text from the accessibility tree, so the button goes back to having no name. This is the classic cause of a button that passes on desktop and fails on mobile. Use the clipping.sr-onlypattern. - Do not rely on a symbol character as the name.
<button>×</button>passes the audit, but screen readers read it as "times" or "multiplication sign". Addaria-label="Close". - Do not put
aria-hidden="true"on the button itself. It hides the control from assistive tech while leaving it keyboard focusable, which is worse than the original problem. - Do not name ten buttons the same thing. Ten "Add to wishlist" buttons pass the audit but are indistinguishable out of context. Include the item:
aria-label="Add Linen Shirt to wishlist". - Do not fix a
<div>by addingrole="button"and stopping there. That moves the failure toaria-command-nameand still leaves it unreachable by keyboard. Use a real<button>.
How do I verify the fix?
- Re-run Lighthouse. The
button-nameaudit should pass and move into "Passed audits". - In Chrome DevTools, select the button and open the Accessibility pane. Computed Properties → Name shows exactly what a screen reader will announce. Empty means it still fails.
- Check at mobile width as well as desktop. Labels hidden at one breakpoint are the most common reason a fix does not stick.
- Test with a screen reader: VoiceOver on Mac (VO+U, then arrow to Form Controls), or NVDA on Windows (Insert+F7, then Buttons). If you cannot tell what a button does from the list alone, the name is not good enough.
- Add axe DevTools or an axe check in your end-to-end tests to catch regressions before they ship.
Related audits
- Links do not have a discernible name, the same problem on anchors
- Tap targets, icon buttons that are also too small to hit
- Image alt attributes, images inside buttons and links
- Color contrast, visual accessibility
Audit your URL at https://lighthouse-md.com.
Audit your page now
Paste your URL, get scores plus a CLAUDE.md plan for Claude Code.