Icon button — accessibility
Keyboard
- Native
<button>: Tab focuses, Enter and Space activate. Withhrefit is a native<a>instead: Tab focuses, Enter activates, and it also gets middle-click / "open in new tab" / "save link as" for free. disabledremoves it from the tab order (native<button disabled>); withhrefthere is no native way to disable a link, sodisabledinstead renders<a aria-disabled="true">with nohref— it stays in the tab order but does nothing, so a screen reader user is not routed to a dead end silently. Prefer omitting the action instead of a disabled link where the screen allows it.- Default
type="button"— pressing Enter inside a form does not submit through it.
ARIA
- No role needed — native
<button>or, withhref, native<a>. - The button has no text, so the accessible name must come from
aria-label(preferred) ortitle. Without one the button is announced as "button" (or "link") only. - Do not rely on the icon's SVG for a name —
<Icon>is decorative. pressedrendersaria-pressed(acrm !3936) — for toggles (format, panel, template/AI in mail compose). It is not used for a menu trigger's open state, which comes fromaria-expanded/aria-haspopupon the trigger instead.
Focus
- Foundation ring from
ds.css:2px solid var(--accent),outline-offset: 1px, following--radius-sm. - No component-specific focus style; hover background is not a focus indicator.
Contrast
Ratios computed from packages/ui/src/tokens/tokens.css:
- Icon at rest
--fg-secondaryon canvas: #7d8184 on #ffffff = 3.93:1 (light); #9a9ca1 on #1b1c1f = 6.20:1 (dark). Light theme passes the 3:1 minimum for graphical objects, not AA 4.5:1 for text (the icon is a graphic). - Icon on hover
--fg: 17.59:1 (light), 14.53:1 (dark). - Focus ring
--accenton canvas: 4.44:1 (light), 3.83:1 (dark).
Known limits
- Rest-state icon contrast in light theme is 3.93:1 — meets the non-text minimum only.
smsize (24px) meets the 24 × 24 CSS px target minimum exactly, with no margin to spare; keep--sp-2or more between adjacentsmbuttons.- No built-in tooltip beyond the native
title; touch users get no tooltip at all, so the icon must be unambiguous.
Source: docs/button/icon-button.a11y.md · GitLab