Copy button
Copies a value.
Styles
ghostdefault
secondary
Show label
falsedefault
true
States
rest
hover
fetching
copied
failed
disabled
Usage
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
valuestring | (() => string | Promise<string>)labelstringshowLabelbooleandefaultfalsevariant, sizeButton variant, sizedefault'ghost', 'icon-sm' or 'sm'timeoutnumberdefault1600onCopy(value: string) => voidforceState'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