Button
A button runs one action or submits a form. It always has a text label.
<tk-button>Save changes</tk-button> <tk-button variant="primary" type="submit">Place order</tk-button>
Anatomy
| Part | What it is |
|---|---|
tk-button |
the element; one Tab stop |
| default slot | the text label, required; it is the accessible name |
icon-start slot |
an optional leading icon |
icon-end slot |
an optional trailing icon |
button part |
the native <button> inside |
Variants
<tk-button variant="primary">Publish</tk-button> <tk-button>Save draft</tk-button> <tk-button variant="outline">Preview</tk-button> <tk-button variant="ghost">Discard</tk-button>
primary: the main action of a view. Use one per view.secondary(default): most buttons, including Cancel and Back.outline: when the button needs a visible edge, such as 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 ; usesecondaryorghostthere.ghost: quiet or repeated actions, such as a row action in a table.
Danger
tone="danger" marks an action that deletes or removes something. It has one look, a
red-tinted button with a red label, whatever variant you set.
<tk-button>Cancel</tk-button> <tk-button tone="danger">Delete account</tk-button>
Name what the action destroys in the label. Color alone doesn't tell everyone.
Shape
shape="round" makes a pill. It works with every variant and size. A joined button group or a
<tk-button shape="round">Follow</tk-button> <tk-button variant="primary" shape="round">Subscribe</tk-button>
Sizes
<tk-button size="small">Small</tk-button> <tk-button>Medium</tk-button> <tk-button size="large">Large</tk-button>
size |
Height | Padding-inline | Label style | Icon |
|---|---|---|---|---|
small |
24px | space-8 |
Label Small (12/16) | icon-size-16 |
medium (default) |
32px | space-12 |
Label Medium (14/20) | icon-size-16 |
large |
36px | space-16 |
Label Medium (14/20) | icon-size-16 |
A long label wraps and the button grows. small is exactly the 24px minimum target size, so
don't scale or squeeze it.
States
<tk-button disabled>Save changes</tk-button> <tk-button variant="primary" loading>Place order</tk-button> <tk-button pressed>Pin to top</tk-button>
Hover, press, and focus need no props. Keyboard focus shows a ring on every button.
disabled: the button can't be focused or clicked, and a danger button turns gray. Prefer keeping the button active and saying what to fix when it's clicked.loading: a spinner replaces the label, the size stays the same, and repeat clicks are ignored. The button stays focusable and tells screen readers it's busy. If you also setdisabled, the button is disabled.pressed: the on state of a toggle. Wrap the button inToggle button rather than setting it yourself.primaryhas no pressed look.
Full width
full-width makes the button fill its container. Use it for stacked actions on narrow
screens, not in desktop forms.
<tk-button variant="primary" full-width>Place order</tk-button> <tk-button full-width>Back</tk-button>
Icons
<tk-button><tk-icon slot="icon-start" name="plus"></tk-icon>Add member</tk-button> <tk-button>Export<tk-icon slot="icon-end" name="chevron-down"></tk-icon></tk-button>
- Put a
intk-iconicon-startto show what the action does, or inicon-endto show what happens next, such as a menu opening. Use one icon per button. - The button sizes the icon to 16px, colors it like the label, and hides it from screen readers.
When to use
- Use a button for an action: save, confirm, open a dialog, delete.
- Use a
link to go somewhere, even when it should look prominent. - Use an
Icon button when there is no visible label.
Content
- Start with a verb and add the object: "Save changes", "Add member".
- Name the action, not the mechanism: "Save and continue", not "Submit".
- Use sentence case, with no articles and no end punctuation.
- Short labels can stand alone: Done, Close, Cancel.
- Let long labels wrap; don't truncate them.
More in
Do / Don't
| ✅ Do | ❌ Don't |
|---|---|
Use one primary per view |
Put two primary buttons side by side |
| Write "Delete account" on a danger button | Write "OK" or "Yes" on a danger button |
Use secondary or ghost on a sunken surface |
Use outline there; its border disappears |
Use loading while an action runs |
Disable the button to show that it's busy |
| Let long labels wrap | Truncate a label or fix the width below it |
| Use a link to go to another page | Make a button navigate |
Related
Icon button : the same button with an icon and no visible label.Toggle button : a button that stays on or off.Button group andSplit button : buttons joined together.Spinner : the indicatorloadingshows.Icon : what the icon slots take.
API
Attributes
| Attribute | Type | Default | What it does |
|---|---|---|---|
variant |
primary | secondary | outline | ghost |
secondary |
emphasis |
tone |
neutral | danger |
neutral |
danger for destructive actions; one look for every variant |
size |
small | medium | large |
medium |
height 24 / 32 / 36px |
shape |
rect | round |
rect |
rounded corners or a pill |
full-width |
boolean | false |
fill the container's width |
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; set by |
type |
button | submit | reset |
button |
set submit to submit the form |
Slots
| Slot | Content |
|---|---|
| default | the text label, required |
icon-start |
one leading tk-icon |
icon-end |
one trailing tk-icon |
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 ; don't use it to restyle one button.
Tokens
| Variant / tone | Rest | Hover | Press | Disabled |
|---|---|---|---|---|
| primary | fill/accent + text/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 | text/accent |
state/accent/hover + text/accent/hover |
state/accent/hover + text/accent/hover |
text/disabled |
tone="danger" |
surface/error + text/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), 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. - A focus ring for keyboard users that is never hidden.
loadingsetsaria-busyand keeps the label as the accessible name.- Icons are hidden from screen readers; the label names the button.
- Every size is at least 24px tall.
Your part:
- Name the destructive action in a danger button's label.
- Use a button for actions and a link for navigation.
- Prefer an active button over
disabled, which can't say what to fix.
| 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. On a sunken surface in light, it disappears.
- Primary label: 4.02:1 with the blue primary color, under the 4.5:1 text minimum; at least 3:1 with every primary color.
- Danger label on hover and press: 3.94:1 in light, under 4.5:1.
- Pressed toggle: in light and dark, on looks the same as hover; high contrast tells them apart. Screen readers always hear the state. If it must be clear at a glance, show it elsewhere too.