Skip to content

Accessibility

An icon button is a native <button> with no visible text — so its whole accessibility rests on two things: an explicit accessible name that stands in for the missing label, and an icon that stays out of the accessibility tree. Get those right and the native element carries the role, keyboard operation, and focus for free. An accessible icon button meets WCAG 2.1 AA: it names its action for assistive technology, keeps its state announced, and stays operable and legible whether the user sees it, hears it, or tabs to it.

  • The glyph and every state — hover, focus, disabled, and the contrast variant placed over imagery — must maintain accessible contrast on every supported surface. Source: WCAG 1.4.3 Contrast (Minimum).
  • With no text to lean on, meaning rests entirely on the glyph — never let colour alone distinguish one state or action from another; the icon’s shape must carry it. Source: WCAG 1.4.1 Use of Color.
  • Focus styles must stay visible, meet contrast requirements on every supported surface, and be clearly distinguishable from hover. Source: WCAG 2.4.7 Focus Visible.
  • Keep the interactive target at least 44 × 44 px — when the visible glyph is smaller, extend the hit area with padding rather than shrinking the target. Source: WCAG 2.5.8 Target Size (Minimum).
  • Use semantic colour tokens (e.g. foreground/neutral/default) rather than fixed values, so the component adapts correctly across themes and surfaces.

An icon button is a native <button>, so it carries the button role, Enter / Space activation, and focus behaviour on its own — never rebuild one from a <div> or <span>. Its one hard requirement is an accessible name: with no visible text, give every icon button an aria-label that names the action (“Close”, “Play video”), not the icon. Beyond naming, the wiring depends on what the button does — a plain action, a toggle, or a disclosure — and the glyph must stay out of the accessibility tree; those per-case roles, names, and states are in the Labelling elements section below. Keep the interactive target at least 44 px high for comfortable touch use — comfortably clearing the WCAG AA minimum. Source: WCAG 2.5.8 Target Size (Minimum).

Give every element the role, name, and state assistive technology needs.

Button

A native <button>, so the role comes for free. Because there’s no visible text, it has no accessible name of its own — set one with aria-label naming the action (“Close”, “Next slide”), never the icon. When a visible label or persistent tooltip exists, wire the name with aria-labelledby instead.

Icon

The glyph is decorative — it restates the action the label already names. Mark it aria-hidden="true" so it never announces as a separate node, leaving the button’s aria-label as the single accessible name.

Toggle / pressed state

A button that flips between two states (bookmark on/off, mute/unmute) keeps aria-pressed in sync — "true" when active, "false" when not. A disclosure button that shows or hides content uses aria-expanded the same way. Keep the aria-label stable across the toggle so it never contradicts the glyph.

Disabled

Use the native disabled attribute rather than a class or aria-disabled alone, so the button leaves the tab order and announces as unavailable. Keep the button in place rather than removing it when the action is only temporarily unavailable, so its position stays discoverable.

Source: WCAG 4.1.2 Name, Role, Value.