Copy button

Copies a value.

Styles

  • ghostdefault

  • secondary

Show label

  • falsedefault

  • true

States

  • rest

  • hover

  • fetching

  • copied

  • failed

  • disabled

Usage

When to use it
Use
The person takes a value into another tool: an ID, an endpoint, an install command, a key.
Use
At the end of a row, a code block or a card that holds one value.
Not for
The value sits in a field the person reads. Use Input.
Not for
The action changes something on this page. Use Button.

Rules

6 rules
Must
Pass label naming what is copied: label="run ID" gives "Copy run ID". Because a row of bare "Copy" buttons gives a screen reader no way to tell which value each one takes.
Must
Pass a function for a secret read on demand; never fetch it on render to fill value. Because a key fetched up front sits in the page for anyone who opens the inspector, and the function pends with the arc only when pressed.
Never
Show a toast or swap the label to confirm a copy; the button confirms in place. Because the glyph cuts to a check and a status region announces it, so a toast says it twice and a swapped label makes the button jump.
Should
Keep it ghost in a row or a code block; make it secondary only when copying is the card's own action. Because a flat pill on every row turns a list into a wall of buttons.
Never
Make a copy button variant="primary". Because copying never moves the task on, so it is never the group's one ink lead.
Should
Set showLabel where the glyph alone could be missed, such as beside a command or in a footer.

State order

7 states, highest first
1
disabled
2
fetching
3
failed
4
copied
5
focus-visible
6
hover
7
rest

Accessibility

4 checks
The button is named "Copy" plus label; the visible Copy and Copied text is aria-hidden so the name never changes.
A status region announces "run ID copied" or how to copy by hand; a second copy clears it for a frame so it is heard again.
Fetching sets aria-busy and keeps focus; a second press does nothing.
Focus is the 2px ink ring; the glyph is aria-hidden.

Keyboard

2 keys
Enter
Copies.
Space
Copies on release.

Edge cases

6 edge cases
Clipboard refused
The glyph turns to the warning and the region says to select and copy by hand.
Slow fetch
The arc turns in place, the width holds, and repeat presses are ignored.
Pressed again while Copied
Copies again and restarts the timer; the announcement repeats.
A fetched value
Writes a ClipboardItem in the same tick as the press, so the user activation holds across the fetch.
Empty value
Disable it; there is nothing to copy.
Reduced motion
The arc stays as a still mark; the glyph cuts as it always does.

API

7 props
value
string | (() => string | Promise<string>)
label
string
showLabel
boolean default false
variant, size
Button variant, size default 'ghost', 'icon-sm' or 'sm'
timeout
number default 1600
onCopy
(value: string) => void
forceState
'fetching' | 'copied' | 'failed'

Tokens

12 tokens
--hover
rgb(5 5 5 / 0.06)
--pressed
rgb(5 5 5 / 0.10)
--text-1
rgb(5 5 5 / 0.80)
--flat-bg
var(--paper)
--flat-ring
var(--line-faint)
--control-sm
26px
--icon-sm
12px
--radius-pill
999px
--type-label-sm
500 12px/1.35 var(--font-sans)
--focus
rgb(5 5 5 / 0.80)
--dur-press
120ms
--dur-spin
800ms

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.