Icon button
An icon button runs one action and shows a single icon instead of a text label. Its label names it for screen readers.
<tk-icon-button label="Search"><tk-icon name="search"></tk-icon></tk-icon-button> <tk-icon-button label="Settings"><tk-icon name="settings"></tk-icon></tk-icon-button> <tk-icon-button label="More actions"><tk-icon name="more-horizontal"></tk-icon></tk-icon-button>
Anatomy
| Part | What it is |
|---|---|
tk-icon-button |
the element; one Tab stop; a fixed square |
| default slot | one icon, required; hidden from screen readers |
pressed slot |
an optional icon shown while pressed, such as a filled twin |
button part |
the native <button> inside; label becomes its accessible name |
Variants
<tk-icon-button label="Edit"><tk-icon name="edit"></tk-icon></tk-icon-button> <tk-icon-button variant="secondary" label="Edit"><tk-icon name="edit"></tk-icon></tk-icon-button> <tk-icon-button variant="outline" label="Edit"><tk-icon name="edit"></tk-icon></tk-icon-button> <tk-icon-button variant="primary" label="Edit"><tk-icon name="edit"></tk-icon></tk-icon-button>
ghost(default): a bare icon with no container. Use it in toolbars, headers, and rows. Unlike a ghostButton , its icon and hover tint are neutral, not accent.secondary: a filled square, for an icon action that needs the weight of a visible control.outline: a bordered square, for a visible edge on a busy surface or in a joinedButton group . Its border is light, so don't place it on a sunken surface such as a neutralBanner orSection message ; useghostorsecondarythere.primary: the main quick action of a bar. Use at most one filled icon button per bar.
Danger
tone="danger" marks an action that deletes or removes something. It has one look, a red
square with a red icon, whatever variant you set.
<tk-icon-button tone="danger" label="Delete file"><tk-icon name="trash"></tk-icon></tk-icon-button>
An icon gives no words at the moment of the click, so a danger icon button must open a
confirmation, such as a confirm
Shape
shape="round" makes a circle. It works with every variant, tone, and size. A joined button
group or a
<tk-icon-button shape="round" label="Add"><tk-icon name="plus"></tk-icon></tk-icon-button> <tk-icon-button variant="secondary" shape="round" label="Share"><tk-icon name="share"></tk-icon></tk-icon-button>
Sizes
<tk-icon-button size="small" label="Close"><tk-icon name="close"></tk-icon></tk-icon-button> <tk-icon-button label="Close"><tk-icon name="close"></tk-icon></tk-icon-button> <tk-icon-button size="large" label="Close"><tk-icon name="close"></tk-icon></tk-icon-button>
size |
Square | Icon | Radius (rect) |
|---|---|---|---|
small |
24×24px | icon-size-16 |
radius-8 |
medium (default) |
32×32px | icon-size-16 |
radius-8 |
large |
36×36px | icon-size-16 |
radius-8 |
The squares match small is exactly
the 24px minimum target size, so don't scale it, give it a negative margin, or let anything
overlap it. The button sizes the icon to 16px at every size.
States
<tk-icon-button disabled label="Edit"><tk-icon name="edit"></tk-icon></tk-icon-button> <tk-icon-button loading label="Download report"><tk-icon name="download"></tk-icon></tk-icon-button>
Hover, press, and focus need no props. Keyboard focus shows a ring on every icon button.
disabled: the button can't be focused or clicked, and a danger button turns gray. Prefer keeping the button active.loading: a spinner replaces the icon, the square stays the same, and repeat clicks are ignored. The button stays focusable, keeps itslabel, and tells screen readers it's busy. If you also setdisabled, the button is disabled.pressed: the on state of a toggle; see below.
Toggle
For on and off actions, such as bookmark, favorite, mute, or pin, set pressed. Put the
filled twin of the icon in the pressed slot and the button swaps them.
<tk-icon-button label="Bookmark" pressed> <tk-icon name="bookmark"></tk-icon> <tk-icon slot="pressed" name="bookmark-filled"></tk-icon> </tk-icon-button>
pressedsetsaria-pressed. A button without the prop is not announced as a toggle.- The label names the action, never the state: "Mute", not "Muted". Screen readers add "pressed" themselves, so a label that flips reads backwards.
- You control
pressed. The button never flips it and fires no change event. Listen forclickand set it, or wrap the button inToggle button , which does it for you. - Every variant except
primaryadds a tint while pressed. Without apressedicon, the tint alone shows the state. - Don't combine
pressedwithtone="danger".
Tooltip
Wrap an icon button in a label text: it shows the button's label, so the two
never disagree.
<tk-tooltip type="label"> <tk-icon-button label="Copy link"><tk-icon name="link"></tk-icon></tk-icon-button> </tk-tooltip>
Do it for any icon that isn't obvious. A bare icon button with a label is still accessible.
When to use
- Use an icon button for an action whose icon everyone knows: close, search, settings, more, favorite. Check that with your users, not only your team.
- Use it where space is tight: toolbars, headers, table rows, card corners.
- Use a
Button with a text label otherwise. People learn text faster than icons. - To open a menu, use a
Menu with an icon button as its trigger.
Content
label is required. It is the accessible name, and the button warns in the console when it
is missing.
- Name the action: "Search", "Rename", "Copy link". Not the icon ("Pencil") and not the state ("Muted").
- Follow Button's label rules: a verb, sentence case, no articles, no end punctuation.
- Use one label per icon across the product. The same icon shouldn't mean "Pin" in one place and "Save" in another.
- In a danger label, name what is deleted: "Delete file".
- Don't use
titlefor the name. Keyboard and touch users never see it.
More in
Do / Don't
| ✅ Do | ❌ Don't |
|---|---|
| Use icon-only for well-known icons and tight toolbars | Replace a labelled button to save space you have |
Keep small at its full 24×24px |
Scale, crop, or overlap a small icon button |
| Use at most one filled icon button per bar | Put two filled icon buttons in one bar |
Use ghost or secondary on a sunken surface |
Use outline there; its border disappears |
Name the action: label="Rename" |
Name the icon ("Pencil") or the state ("Muted") |
| Confirm before a danger action runs | Delete on the first click |
Give a toggle a filled twin in the pressed slot |
Change the label when pressed flips |
Related
Button : the same button with a visible label.Toggle button : wraps an icon button and flipspressedfor you.Tooltip : shows the label on hover and focus.Menu : uses an icon button as its trigger.Spinner : the indicatorloadingshows.Icon : what the slots take.
API
Attributes
| Attribute | Type | Default | What it does |
|---|---|---|---|
label |
string | required | the accessible name; names the action |
variant |
primary | secondary | outline | ghost |
ghost |
emphasis |
tone |
neutral | danger |
neutral |
danger for destructive actions; one look for every variant |
size |
small | medium | large |
medium |
square 24 / 32 / 36px |
shape |
rect | round |
rect |
rounded corners or a circle |
disabled |
boolean | false |
not focusable, not clickable, left out of the form |
loading |
boolean | false |
spinner, same size, repeat clicks ignored, aria-busy |
pressed |
boolean | unset | toggle on state and aria-pressed; you set it |
type |
button | submit | reset |
button |
set submit to submit the form |
Slots
| Slot | Content |
|---|---|
| default | one tk-icon, required |
pressed |
one tk-icon shown while pressed, optional |
Events
No custom events. Listen for click; disabled and loading block it.
CSS
::part(button): the native<button>.--tk-button-radius: sets the corners; it overridesshape. For components that join buttons, such asButton group .
Tokens
| Variant / tone | Rest | Hover | Press | Disabled |
|---|---|---|---|---|
| primary | fill/accent + icon/accent/on-fill |
fill/accent/hover |
fill/accent/active |
surface/disabled + text/disabled |
| secondary | surface/subtle + text/default |
state/hover |
state/press |
surface/disabled + text/disabled |
| outline | border/subtle + text/default |
state/hover |
state/press |
border/disabled + text/disabled |
| ghost | icon/default |
state/hover |
state/press |
text/disabled |
tone="danger" |
surface/error + icon/error |
state/error/hover |
state/error/press |
surface/disabled + text/disabled |
state/* tokens are translucent tints laid over the button's rest color. Pressed buttons use
state/on (state/on-hover under the pointer) with an icon/default glyph, plus
border/selected on outline. The focus ring is border/accent/focus on every button.
Values per theme:
Accessibility
Built in:
- A native
<button>: Tab reaches it, Space and Enter activate it, forms see it. labelbecomes the accessible name; slotted icons are hidden from screen readers.pressedsetsaria-pressed, which stays underdisabledandloading.loadingsetsaria-busyand keeps the name.- A focus ring for keyboard users that is never hidden.
- Every size is at least 24×24px.
Your part:
- Check that people understand the icon; if in doubt, use a
Button with text. - Write the label as the action, and keep it the same when
pressedchanges. - Open a confirmation before a danger action runs.
- Wrap icons that aren't obvious in a
labelTooltip.
| Key | Action |
|---|---|
Tab |
moves focus to the button |
Space / Enter |
activates it; with type="submit", submits the form |
Contrast limits
- Outline border: 1.33:1 in light and 2.00:1 in dark, under the 3:1 minimum; 4.22:1 in high contrast. With no label or fill, the border is all that shows the button. On a sunken surface in light, it disappears.
- Pressed toggle: in light and dark, on looks the same as hover; high contrast tells them
apart. Screen readers always hear the state; the
pressedicon makes it visible.