ADA Compliance Professionals

    Buttons must have discernible text

    Last updated:

    Who it helps:
    Blind
    Standard:
    WCAG 2.2 Level AA

    Buttons must not lack discernible text (accessible name)

    A button needs a non-empty accessible name that describes its action.

    This applies to native buttons, input buttons, custom elements with role="button", and menu items. Users of screen readers and voice control depend on that name to understand and operate the control.

    Why It Matters

    Without an accessible name, assistive technologies announce only the role (e.g., “button”) with no purpose. People cannot tell what will happen when they activate it.

    Users of speech input need a label to say out loud (e.g., “Click Save”). Icon-only or empty buttons block this interaction entirely.

    Vague or missing names also slow down navigation for users with cognitive disabilities who rely on clear, action-oriented wording.

    Common Causes

    • Empty <button> with no text content.
    • Icon-only buttons without aria-label or aria-labelledby.
    • aria-label set to an empty string.
    • aria-labelledby pointing to missing or empty elements.
    • Using value on <button> (value does not name a <button> element).
    • Custom elements (div/span) with role="button" but no accessible name.

    How to Fix

    1. Prefer visible, descriptive text inside native buttons.
      • Keep labels short and action-oriented (e.g., “Save”, “Add to cart”).
    2. For icon-only buttons, provide an accessible name.
      • Use aria-label with meaningful text, or aria-labelledby that references existing, non-empty text.
    3. Name input buttons correctly.
      • For <input type="button|submit|reset">, set a non-empty value, or use aria-label/aria-labelledby.
    4. Ensure references resolve.
      • Every id in aria-labelledby must exist and reference elements with non-empty text. Do not point to hidden or empty nodes.
    5. Avoid empty ARIA and fragile fallbacks.
      • Do not leave aria-label empty. Title can be used as a fallback in the naming computation, but it is not reliable as the sole label; prefer visible text or ARIA.
    6. Custom buttons must have a name and keyboard support.
      • Elements with role="button" need an accessible name and must respond to Enter and Space.
    7. Match visible label and accessible name when possible (recommendation).
      • Aligns with WCAG 2.5.3 Label in Name so what users see is what AT announces.

    How to Test

    Keyboard check

    • Tab through the page. Each button should receive focus and be operable with Enter/Space.
    • While focused, confirm the visible label (if any) clearly describes the action.

    Screen reader check

    • Desktop (NVDA/JAWS + Windows, VoiceOver + macOS): Navigate by buttons. Each button should be announced with a meaningful name and correct role.
    • Confirm icon-only buttons are announced with a useful label (e.g., “Search, button”).

    Mobile/touch check

    • iOS VoiceOver / Android TalkBack: Swipe to each button. Ensure the spoken name is present and descriptive. Double-tap activates the expected action.

    Quick checklist

    • Every button has a non-empty accessible name.
    • Icon-only buttons use aria-label or aria-labelledby.
    • aria-labelledby targets exist and contain text.
    • Input buttons have a value or ARIA name.
    • Custom role="button" elements include a name and support Enter/Space.
    • Visible label words appear in the accessible name when applicable.

    Good Example

    HTML
    <button type="button">Save changes</button>
    
    <button type="button" aria-label="Search">
      <svg aria-hidden="true" width="16" height="16"><!-- magnifier --></svg>
    </button>
    
    <span id="archive-label" class="visually-hidden">Archive message</span>
    <button type="button" aria-labelledby="archive-label">
      <svg aria-hidden="true" width="16" height="16"><!-- box icon --></svg>
    </button>
    
    <input type="submit" value="Place order">
    
    <div role="button" aria-label="Close dialog" tabindex="0"></div>

    Bad Example

    HTML
    <!-- Empty button -->
    <button></button>
    
    <!-- Icon-only with no name -->
    <button><svg width="16" height="16"><!-- x icon --></svg></button>
    
    <!-- aria-labelledby points to missing element -->
    <button aria-labelledby="missing-id"></button>
    
    <!-- Uses value on <button>, which does not name the control -->
    <button value="Proceed"></button>
    
    <!-- Custom button without a name -->
    <div role="button" tabindex="0"></div>

    Quick Checklist

    • Non-empty accessible name on every button.
    • Prefer visible text; add ARIA for icon-only controls.
    • Do not use empty aria-label and fix broken aria-labelledby references.
    • For input buttons, set a value or ARIA name.
    • Custom role="button" supports Enter/Space and has a name.
    • Names are specific to the action (avoid “Click here”).
    • Visible label and accessible name align where possible.
    • Re-test with a screen reader after changes.