Copy Button
CopyButton for any surface (toolbars, code blocks, cards), CopyField for the classic read-only input with a copy button beside or inside it, and the useCopyToClipboard hook when you want the behaviour with your own markup. The write uses the async Clipboard API and falls back to a hidden textarea where that is unavailable, and a failed write shows a brief "Failed" state instead of lying about success.Copy Button
Click it — the icon pops to a check and the label swaps to Copied! for two seconds.
value- is the text written to the clipboard.
label- is the resting text and
copiedLabelthe confirmation —CopyandCopied!by default.
Installation
New project? Follow the installation guide to set up Tailwind CSS, shadcn, the cn helper and lucide-react, register the @algorize-ui registry once, then copy your styles from the Themes page.
Install Copy Button
components/ is written into your project. Copy any snippet from a Usage tab above and it runs.
Install dependencies
Nothing beyond the shared setup — Copy Button needs only the cn helper and lucide-react, which the installation guide already put in place.
Examples
Variants
variant- is
"solid"(default),"soft","outline"or"ghost". Every variant flashes the theme colour on success so the confirmation reads even on a quiet button.
Sizes
size- is
"sm","md"(default) or"lg"— height, padding and icon scale together.
Icon only
- Set
iconOnly - for a square button with no label — for toolbars and table rows. It keeps an accessible name that flips to
Copiedafter a successful write.
Copy field
The share-link pattern: a read-only input with the button beside it.
- Use
CopyField - to render the value in a read-only input with a
CopyButtonnext to it. Clicking the input selects everything;buttonPropsforwards labels, variant and timeout to the button.
Inset button
- Set
inset - on
CopyFieldto tuck an icon-only ghost button inside the field's right edge;prefixadds an icon on the left.
In a code block
- Combine
variant="ghost" - with a
classNameto blend the button into any toolbar — here a terminal header that follows the light and dark theme.
Custom labels & timing
timeout- is how long the copied state lingers in milliseconds (default
2000).onCopyfires with the value and whether the write succeeded.
The hook on its own
useCopyToClipboard(timeout?), exported from copy-button-hooks.ts (installed beside the block), returns { copy, status, copied }. copy(text) resolves to a boolean, and status is "idle" | "copied" | "error", resetting itself after timeout ms — everything the button does, for your own markup.Features
Inline confirmation
The feedback lives in the button itself — a popping check and a rising label — so nothing else on the page has to move.
Honest states
A blocked clipboard shows Failed rather than a false success, and onCopy tells you which it was.
Works everywhere
Uses the async Clipboard API and falls back to a hidden textarea on older browsers and non-secure origins.
Accessible
A polite live region announces the change; icon-only buttons carry a name that updates to Copied.
Best Practices & Guidelines
Say what was copied
Prefer specific labels — Copy Link, Code copied — over a bare Copy when more than one thing on the screen could be copied.
Don't close the surface on copy
Let the confirmation play before dismissing a dialog or popover — closing on click hides the only feedback the user gets.
Props Reference
<CopyButton> Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | Required | The text written to the clipboard. |
label | ReactNode | "Copy" | Resting label. |
copiedLabel | ReactNode | "Copied!" | Label shown after a successful write. |
errorLabel | ReactNode | "Failed" | Label shown when the clipboard write is refused. |
iconOnly | boolean | false | Hide the label and render a square icon button with an accessible name. |
timeout | number | 2000 | How long the copied / failed state lingers, in ms. |
variant | "solid" | "soft" | "outline" | "ghost" | "solid" | Visual style. |
size | "sm" | "md" | "lg" | "md" | Height, padding and icon size. |
color | "primary" | "indigo" | "rose" | "emerald" | "zinc" | string | "primary" | Theme colour for the solid / soft fills, the success flash and the focus ring. Accepts hex codes. |
onCopy | (value: string, ok: boolean) => void | — | Fires after the write with the value and whether it succeeded. |
<button> attribute (className, disabled, onClick…) is forwarded. Calling preventDefault() in your own onClick cancels the copy.<CopyField> Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | Required | Shown in the read-only input and copied by the button. |
label | string | — | Bold label above the field. |
buttonProps | Omit<CopyButtonProps, "value"> | — | Forwarded to the embedded button — labels, variant, timeout, onCopy… |
inset | boolean | false | Render an icon-only ghost button inside the field's right edge instead of a full button beside it. |
prefix | ReactNode | — | Icon or adornment on the field's left side. |
selectOnClick | boolean | true | Select the whole value when the input is clicked. |
size | "sm" | "md" | "lg" | "md" | Field and button height. |
color | string | "primary" | Theme colour shared by the button and the field's focus ring. |