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: a job ID, an endpoint, a connection string, a command.
Use
At the end of a row, a code block or a field 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="job ID" gives "Copy job ID". Because a column 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 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.
Never
Make a copy button the slab by restyling it or wrapping it in a primary Button. Because copying never moves the task on, so it is never the group's one yellow action.
Should
Keep it ghost in a row or a code block; make it secondary only when copying is the region's own action. Because an edged button on every row turns a list into a wall of boxes.
Should
Set showLabel where the glyph alone could be missed, such as beside a command or in a panel head.

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 words are aria-hidden so the name never changes.
A status region announces "job 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.
Failed turns the glyph and word to the failure colour and the warning glyph, so it never rests on colour alone.

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 pending mark steps in place of the glyph, 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 pending mark stands still; the glyph cuts as it always does.

API

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

Tokens

11 tokens
--hover
rgb(22 21 18 / 0.04)
--pressed
rgb(22 21 18 / 0.08)
--text-1
#161512
--text-2
#55524a
--fail-text
#b3261e
--line
#e2dfd5
--control-sm
26px
--icon
16px
--type-label-sm
400 12px/16px var(--font-mono)
--focus
#7a5d00
--dur-press
80ms

Install

For your coding agent

GitHub

Please star me pookie

198

A new design system every week

Leave your email before you copy the prompt.