AccessibilityApril 28, 20269 min read

Accessible Button Names: Fixing the button-name Violation

If a screen reader user lands on a button on your site and only hears the word “button,” you have a button-name violation. That single missing string is enough to abandon a checkout, a sign-up, or a navigation menu.

1. What is the button-name violation?

axe-core's button-name rule fires when a <button> (or any element with role="button") has no accessible name. It is a direct violation of WCAG 2.1 4.1.2 Name, Role, Value (Level A) — meaning even the lowest tier of conformance is broken.

The "accessible name" is the string a screen reader (NVDA, JAWS, VoiceOver, TalkBack) reads when the button receives focus. Without one, the device just announces "button" — and that's all.

2. Why it matters

It's not just blind users. Anyone using voice control (Apple Voice Control, Dragon NaturallySpeaking, Android Voice Access) needs that name to issue a command. To say "click the Add to cart button," the system must recognize it as "Add to cart."

Scale: across recently crawled sites, Keysonar found over 22,000 button nodes failing this rule — meaning hundreds of users per site are excluded from primary interactions. It is consistently one of the top three violations in any large-scale accessibility audit.

3. When does it fire?

Five patterns we see repeatedly in production crawls:

  1. Empty button: No content at all.
  2. Icon only: SVG, FontAwesome, or a CSS background icon — no readable text.
  3. Image only: An <img> child with no alt.
  4. All text hidden by aria-hidden: Removed from the accessibility tree.
  5. Text hidden by display:none: Hidden from both the screen and the reader.

4. The fixes

4.1 Icon buttons

The most common offender on e-commerce: cart, search, heart, share. Often there is no text besides the icon, so the button is announced as just "button."

Yanlış / WrongScreen reader: 'button'
<button class="cart-btn">
  <svg viewBox="0 0 24 24">...</svg>
</button>
Doğru / RightScreen reader: 'Add to cart, button'
<button class="cart-btn" aria-label="Add to cart">
  <svg aria-hidden="true" viewBox="0 0 24 24">...</svg>
</button>

4.2 Modal close button (×)

Yanlış / Wrong
<button onclick="close()">
  <span aria-hidden="true">×</span>
</button>
Doğru / Rightsr-only: visually hidden, exposed to AT
<button onclick="close()" type="button">
  <span aria-hidden="true">×</span>
  <span class="sr-only">Close</span>
</button>

<style>
  .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;
  }
</style>

4.3 Image button

Yanlış / Wrong
<button>
  <img src="/icons/search.svg">
</button>
Doğru / RightThe img alt becomes the button name
<button>
  <img src="/icons/search.svg" alt="Search">
</button>

4.4 React / Next.js components

Yanlış / WrongIcon only, no name
<button onClick={addToWishlist}>
  <Heart className="w-5 h-5" />
</button>
Doğru / Right
<button
  onClick={addToWishlist}
  aria-label={t("product.addToWishlist")}
>
  <Heart aria-hidden className="w-5 h-5" />
</button>

On a multi-language site, source the label from the translation dictionary. An English aria-label on a Turkish page will be read by an English speech engine and become unintelligible to Turkish-speaking users.

5. How the accessible name is computed

The browser walks this priority list and uses the first non-empty result:

  1. aria-labelledby (references the text content of another element)
  2. aria-label
  3. The button's own text content (text, img alt, etc.)
  4. title attribute (least reliable — avoid)
Yanlış / WrongUser sees 'Add to cart' but reader says 'Confirm'
<button aria-label="Confirm">
  Add to cart
</button>
Doğru / Right
<button>Add to cart</button>

6. Cases that get missed

  • Late-rendered SPA buttons: Buttons inside modals or tabs that mount on user interaction. Static scanners may miss them — your crawler should hit them after the click that reveals them.
  • Symbol text (×, +, →): A character like × may be read as "multiplication sign" or skipped entirely. Symbols are not semantics. Always pair with sr-only text ("Close").
  • title attribute: Invisible on touch devices and inconsistent across screen readers. Do not rely on it as a name source.
  • Icon library defaults: FontAwesome, Material Icons, Heroicons — none of them set an aria-label automatically. Each consuming button must provide its own.

7. How to test

  1. axe DevTools browser extension: instant per-page scan. Best for fast developer feedback during build.
  2. Keysonar SEO Tools: site-wide automated scan, list of affected pages, regression tracking over time. No DevTools required.
  3. NVDA (Windows) / VoiceOver (macOS): manual screen-reader test for real-user feel. Tab through every button, write down what you hear.
  4. Lighthouse: Chrome DevTools accessibility audit — shorter report, CI-friendly.

8. Quick checklist

  • Every <button> has visible text, an aria-label, or aria-labelledby.
  • Icon-only buttons have an aria-label in the same language as the page.
  • Buttons containing <img> have a non-empty alt or a parent aria-label.
  • Symbol-only content (×, +) is paired with sr-only descriptive text.
  • No redundant aria-label on buttons that already have visible text.
  • Decorative icons inside buttons have aria-hidden="true".
  • Late-mounted buttons (modals, dropdowns) are tested too.
  • title attribute is NOT used as the accessible name source.

9. References

  • WCAG 2.1 SC 4.1.2 — Name, Role, Value (Level A)
  • WAI-ARIA Authoring Practices: Button pattern
  • HTML Living Standard — The button element
  • Accessible Name and Description Computation 1.2 (W3C)

Catch these violations automatically across your site

Keysonar SEO Tools crawls every page, runs the full axe-core ruleset including button-name, and gives you the exact list of affected URLs.

Start free