CopyButton
Copy a value, and say that it happened.
Why it exists
Seven of these existed hand-rolled — Echo, Ivy twice, Grove twice, Hana, Root — plus two more inside these docs, which is the tell: the design system was rebuilding the button it had not shipped.
The copies diverged, and one of them was right
navigator.clipboard requires a secure context, so it is simply absent over plain http — which is the case for anyone testing from a phone against a laptop's LAN address, and for every app in this suite in local development. Six of the seven buttons silently did nothing there. Echo's carried a textarea fallback; that is the one kept.
The swatches on /foundations/colour and the code tabs on this site both run on useCopy.
A value that exists to be copied
Wrapping, never truncated. A truncated secret or DNS record looks complete and is not, and the person pasting it has no way to tell — the ellipsis sits at the end of a string they have never seen in full.
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvn2Xy8QpKq3mR7wLd0In both themes
light
dark
Guidance
Use it when
- A value someone will paste somewhere else: a key, a correlation id, a DNS record, a command.
- CopyField when the value itself should be on screen in full.
- useCopy when the control is not a button — a swatch, a row, a table cell.
Reach for something else when
- Prose. Copying a paragraph is what selection is for.
- A value the page can act on itself — offer the action, not the string.
- An icon-only button with no aria-label. Then it is announced as “button”.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | — | What lands on the clipboard. |
| label | string | "Copy" | The resting label. Pass "" for icon-only — then aria-label is required. |
| confirmFor | number | 1600 | Milliseconds the confirmation stays up. |
| variant | "outline" | "ghost" | "default" | "danger" | "outline" | Inherited from Button. |
Accessibility
The confirmation is announced from a separate aria-live node rather than the button itself. Putting the live region on the button makes a screen reader re-announce the whole control — label, role and all — when only one word changed. And a failed copy stays silent: a denied clipboard permission is the browser's decision, not an error worth a red banner, and the value is on screen and selectable either way.