Icon Button
stableIconButton is a compact native button whose visible content is an icon rather than a text label. It is intended for familiar, frequently used actions where space is limited and the icon’s meaning is clear from established conventions or surrounding context.
Because the action is not visibly named, every IconButton requires an accessible label that describes what the control does.
Basic usage
Provide a familiar icon and a non-empty aria-label that describes the action.
---
import { IconButton } from "@ulubit/ui";
---
<IconButton aria-label="Close dialog">
<CloseIcon />
</IconButton>Use an ordinary Button when visible text would make the
action clearer.
Accessible label
Every icon button requires a non-empty aria-label because its icon is hidden
from assistive technologies.
The label must describe the action, not the icon’s appearance.
Prefer:
Copy linkClose dialogDelete projectOpen settings
Avoid:
Copy iconXTrash canButton
<IconButton aria-label="Copy link">
<CopyIcon />
</IconButton>Variants
Choose a variant based on the action’s purpose and priority.
| Variant | Use for |
|---|---|
primary |
A high-emphasis icon action |
secondary |
A visible alternative or supporting action |
tertiary |
Most compact supporting actions |
danger |
A destructive icon action |
tertiary is the default because icon-only controls are usually supporting actions that should not compete with the page’s primary action.
Use a specific accessible label for danger actions, such as Delete project rather than Delete when the affected item is not otherwise clear.
IconButton uses the same variant and disabled color tokens as Button. See Button color tokens for the complete reference.
Sizes
Icon buttons support sm, md, and lg. Size controls both the square target
and the icon dimensions.
| Size | Use for |
|---|---|
sm |
Compact interfaces with sufficient spacing between controls |
md |
Most icon-button uses |
lg |
Spacious interfaces or intentionally larger targets |
md is the default.
<IconButton aria-label="Edit item" size="sm">
<EditIcon />
</IconButton>
<IconButton aria-label="Edit item">
<EditIcon />
</IconButton>
<IconButton aria-label="Edit item" size="lg">
<EditIcon />
</IconButton>Disabled state
Use the native disabled attribute when the action is unavailable.
<IconButton aria-label="Delete project" variant="danger" disabled>
<TrashIcon />
</IconButton>A disabled icon button cannot be focused or activated. Provide nearby context when the reason it is unavailable would otherwise be unclear.
Loading state
Use loading while an action is being processed.
<IconButton
aria-label="Delete project"
variant="danger"
loading
loadingLabel="Deleting project"
>
<TrashIcon />
</IconButton>While loading, the component shows a progress indicator, disables activation,
sets aria-busy="true", and uses loadingLabel as its accessible name.
loadingLabel must be non-empty and should describe the operation in progress.
The consuming application remains responsible for managing the asynchronous
operation and announcing important success or failure results.
The loading prop controls the state rendered by Astro. If loading changes
after the page loads, the consuming application must update the button from
client-side code.
Tooltips
aria-label provides an accessible name, but it does not create visible help
text.
Use a text Button when the icon is not clear enough on its own. Do not add a
title attribute as a substitute for a well-designed visible label or a proper
Tooltip component.
Boundaries
IconButton performs an action. It does not provide:
- navigation behavior
- toggle or pressed-state behavior
- automatic tooltips
Use a native <a> for icon-only navigation. Use
ButtonLink when the navigation control has a
visible text label.
Introduce a dedicated toggle-button pattern only when an action requires a persistent pressed state.
Accessibility
IconButton renders a native <button> and retains its built-in keyboard and
focus behavior. The required aria-label supplies its accessible name, while
the decorative icon is hidden from assistive technologies.
API
The component accepts valid native <button> attributes except aria-labelledby, and aria-busy. aria-label is required through the component API.
| Property | Type | Default | Description |
|---|---|---|---|
aria-label |
string |
Required | Provides the button’s accessible name. |
variant |
"primary" | "secondary" | "tertiary" | "danger" |
"tertiary" |
Defines visual hierarchy and intent. |
size |
"sm" | "md" | "lg" |
"md" |
Defines the square target and icon dimensions. |
loading |
boolean |
false |
Displays the loading state and prevents repeated activation. |
loadingLabel |
string |
— | Provides the accessible name while loading. Required when loading is true. |
type |
"button" | "submit" | "reset" |
"button" |
Defines native button behavior. |
disabled |
boolean |
false |
Prevents interaction with the button. |
class |
string |
— | Adds a class alongside the component’s internal classes. |
| Default slot | AstroComponentFactory |
Required | Provides the decorative icon. |
Native attributes such as name, value, form, aria-describedby,
aria-controls, and data-* are forwarded to the underlying <button>.