Sheath rule
a11y-button-accessible-name
Buttons must have an accessible name for screen readers.
- Package
- Core
- Category
- Accessibility
- Default severity
- error by default
- Auto-fix
- Manual fix
#Why
Buttons need text content, aria-label, aria-labelledby, or title to be accessible to screen reader users. Without an accessible name, users cannot understand what action the button performs.
#Examples
#Bad
<!-- Empty button -->
<button></button>
<!-- Icon-only button without accessible name -->
<button><i class="icon-save"></i></button>
<!-- Input button without value -->
<input type="button">
<!-- Image input without alt -->
<input type="image" src="submit.png">
#Good
<!-- Text content -->
<button>Save Changes</button>
<!-- Icon with aria-label -->
<button aria-label="Save"><i class="icon-save"></i></button>
<!-- A child SVG may contribute the name -->
<button><svg aria-label="Save"></svg></button>
<!-- Using aria-labelledby -->
<span id="btn-label">Submit Form</span>
<button aria-labelledby="btn-label"><i class="icon-check"></i></button>
<!-- Input with value -->
<input type="button" value="Click Me">
<!-- Submit/reset have default accessible names -->
<input type="submit">
<input type="reset">
<!-- Image input with alt -->
<input type="image" src="submit.png" alt="Submit Order">
<!-- Using title attribute -->
<button title="Close dialog"><i class="icon-x"></i></button>
<!-- Native label association -->
<label for="save-button">Save changes</label>
<button id="save-button"></button>
#Notes
- Text inside
hidden,inert,aria-hidden="true",script,style, ortemplatedescendants does not name the button. A hidden element explicitly referenced byaria-labelledbycan still provide a name. - Visible text serves everyone, not only screen reader users
aria-labelis useful for icon-only buttons- Submit and reset inputs have browser-default accessible names ("Submit" and "Reset") when
valueis omitted; an explicitly emptyvaluehas no accessible name - Image inputs require an
altattribute for accessibility - Opaque attribute spreads such as
{{ $attributes }}make the final name unknowable and are not checked. Every explicit branch that produces an exposed button must have a name - A static
aria-labelledbyvalue names the button only when at least one referencedidexists in the rendered document - A button with a non-empty Alpine
x-textorx-htmlexpression, or Livewirewire:textexpression (<button wire:text="label"></button>), is treated as having content because client-side code fills the empty body before the user interacts with it. Bare, empty, and whitespace-only expressions do not count
#References
- WCAG 4.1.2 Name, Role, Value - Level A success criterion for accessible names
- MDN: Accessible Name - How browsers compute accessible names
#Related Rules
- a11y-anchor-content - Similar requirement for links
- best-practices-button-type - Require type attribute on buttons