Icon Button
An icon button is a native <button> containing only an icon glyph, image, or SVG. Because icon-only buttons have no visible text, this component requires an accessible label so that screen readers can announce the purpose of the action.
Use it for compact, recognizable actions such as close, delete, edit, share, favorite, and toolbar controls where a label would be visually redundant once a user understands the icon.
Implementation Notes
- Uses a native
<button>element for inherent keyboard and accessibility support labelprop is required — it setsaria-labelso the button has an accessible name- Defaults to
type="button"to prevent accidental form submissions aria-pressedis rendered only whenpressedis provided (toggle button pattern)- Native
disabledattribute prevents click events automatically - Children render the icon content (svg, emoji, glyph) and are decorative
Props
label: string (required) -- aria-labeltype: "button" | "submit" | "reset" (default: "button")disabled: boolean (default: false)pressed: boolean | undefined (default: undefined) -- toggle button stateonclick/onClick: callback (optional) -- click handlerchildren: slot -- the icon content...restProps: any additional HTML attributes
Usage
Close button with required label:
<IconButton label="Close" onclick={handleDismiss}>
<svg>...</svg>
</IconButton>
Toggle favorite:
<IconButton label="Favorite" pressed={isFavorited} onclick={toggleFavorite}>
★
</IconButton>
Disabled icon action:
<IconButton label="Delete" disabled>
<svg>...</svg>
</IconButton>
Keyboard Interactions
- Tab: Focus the button
- Enter: Activate the button
- Space: Activate the button
- (All handled natively by
<button>element)
ARIA
- Implicit
buttonrole from<button>element aria-labelis the entire accessible name (required)aria-pressedfor toggle button state (when provided)aria-disabledfrom nativedisabledattribute
When to Use
- Use for compact actions where the icon meaning is universally recognized (close, search, edit, delete).
- Use in toolbars and tight UI regions where a labeled button would be too wide.
- Use the toggle pattern (with
pressed) for binary state controls (mute/unmute, follow/unfollow).
When Not to Use
- Do not use when the action is unfamiliar or ambiguous — use a labeled Button.
- Do not use as a primary call to action — use Button so users see the verb.
- Do not omit
label— icon-only buttons without an accessible name fail WCAG.
Headless
Renders a native <button> with the required aria-label. The icon glyph, its size, focus indicator, hover state, and any visual treatment are entirely the consumer's responsibility.
Styles
Consumer CSS targets the icon-button class. Provide a minimum 44×44 px touch target, a clear focus indicator, and hover/active visual feedback.
Testing
- Verify the component renders a
<button>element with classicon-button - Verify
aria-labelis present and equals thelabelprop - Verify
typedefaults to"button"when not provided - Verify
aria-pressedis rendered only whenpressedis provided - Verify
disabledattribute is applied whendisabledis true - Verify the click handler fires on Enter, Space, and click
Advice
- Designers: Use icons that are universally recognizable. Maintain a 44×44 px touch target and a high-contrast focus ring.
- Developers: Always supply a
labelprop. Thepressedprop is for toggle semantics only — leave itundefinedfor ordinary action buttons.
Related components
button— a generic clickable button elementfloat-button— a floating action button anchored to a viewport cornertool-bar-button— one action button in a tool bar
References
- WAI-ARIA Button Pattern: https://www.w3.org/WAI/ARIA/apg/patterns/button/
- WCAG 4.1.2 Name, Role, Value: https://www.w3.org/WAI/WCAG22/Understanding/name-role-value