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.
Example
Show demo markup
<div class="icon-button" aria-label="a button containing only an icon with a required accessible label">IconButton</div>
Usage example
<script lang="ts">
import IconButton from './IconButton.svelte';
function close() { /* … */ }
</script>
<IconButton label="Close dialog" onclick={close}>
<span aria-hidden="true">×</span>
</IconButton>
Show Svelte source
// In your Svelte component:
import IconButton from "lily-design-system-svelte-headless/components/IconButton/IconButton.svelte";
<IconButton>IconButton</IconButton>
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>
Props
label: string (required) -- aria-label
type: "button" | "submit" | "reset" (default: "button")
disabled: boolean (default: false)
pressed: boolean | undefined (default: undefined) -- toggle button state
onclick / onClick: callback (optional) -- click handler
children: slot -- the icon content
...restProps: any additional HTML attributes
Keyboard Interactions
- Tab: Focus the button
- Enter: Activate the button
- Space: Activate the button
- (All handled natively by
<button> element)
ARIA
- Implicit
button role from <button> element
aria-label is the entire accessible name (required)
aria-pressed for toggle button state (when provided)
aria-disabled from native disabled attribute
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 class icon-button
- Verify
aria-label is present and equals the label prop
- Verify
type defaults to "button" when not provided
- Verify
aria-pressed is rendered only when pressed is provided
- Verify
disabled attribute is applied when disabled is 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
label prop. The pressed prop is for toggle semantics only — leave it undefined for ordinary action buttons.
Implementation Notes
- Uses a native
<button> element for inherent keyboard and accessibility support
label prop is required — it sets aria-label so the button has an accessible name
- Defaults to
type="button" to prevent accidental form submissions
aria-pressed is rendered only when pressed is provided (toggle button pattern)
- Native
disabled attribute prevents click events automatically
- Children render the icon content (svg, emoji, glyph) and are decorative
Related components
button — a generic clickable button element
float-button — a floating action button anchored to a viewport corner
tool-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
Canonical contract
Generated from this component's canonical metadata — the machine-checked source the implementations are held to.
Metadata
- Component: icon-button
- PascalCase: IconButton
- Description: a button containing only an icon with a required accessible label
- Status: beta — implemented and unit-tested in all seven frameworks with an axe-clean demo page; not yet exercised in composed flows
- HTML tag: <button>
- CSS class: .icon-button
- Interactive: yes
ARIA
- Implicit
button role from <button> element aria-label is the entire accessible name (required) aria-pressed for toggle button state (when provided) aria-disabled from native disabled attribute
Keyboard
- Tab: Focus the button
- Enter: Activate the button
- Space: Activate the button
- (All handled natively by
<button> element)
Props
label: string (REQUIRED) -- aria-label type: "button" | "submit" | "reset" (default: "button") disabled: boolean (default: false) pressed: boolean | undefined (default: undefined) -- toggle state onclick / onClick: callback (optional) children: slot -- icon content ...restProps: any additional HTML attributes