Buttons must have discernible text
Last updated:
Related Guides
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-labeloraria-labelledby. aria-labelset to an empty string.aria-labelledbypointing 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
- Prefer visible, descriptive text inside native buttons.
- Keep labels short and action-oriented (e.g., “Save”, “Add to cart”).
- For icon-only buttons, provide an accessible name.
- Use
aria-labelwith meaningful text, oraria-labelledbythat references existing, non-empty text.
- Use
- Name input buttons correctly.
- For
<input type="button|submit|reset">, set a non-empty value, or use aria-label/aria-labelledby.
- For
- Ensure references resolve.
- Every id in
aria-labelledbymust exist and reference elements with non-empty text. Do not point to hidden or empty nodes.
- Every id in
- Avoid empty ARIA and fragile fallbacks.
- Do not leave
aria-labelempty. 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.
- Do not leave
- Custom buttons must have a name and keyboard support.
- Elements with
role="button"need an accessible name and must respond to Enter and Space.
- Elements with
- 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-labeloraria-labelledby. aria-labelledbytargets 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
<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
<!-- 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-labeland fix brokenaria-labelledbyreferences. - 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.