Skip to content

shadcn.io is an independent project built on shadcn/ui

Buttons

Free

Copy Button for Radix UI

Copies text to the clipboard and swaps its icon for a check. For React with Radix UI, next to code, links and keys people need to paste.

Press it and content goes to the clipboard: the copy icon turns into a check for three seconds, then comes back. If the clipboard refuses, a cross shows instead, so nobody walks away thinking they copied something they didn't.

Use it beside an install command, a share link, an API key or an order number. It wraps the Button, so variant and size work as usual; it's icon-only by default, and a label next to the icon makes it a regular button. The icons cross-fade and scale with CSS transitions, with no animation library, and with reduced motion they only fade.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Usage

import { CopyButton } from "@/components/ui/copy-button";
<CopyButton aria-label="Copy link" content="https://example.com/invite/7Hq2" />

Demos

Reset Delay

resetDelay is how long the check stays, in milliseconds, and the default is 3000. A short one suits a value people copy again and again; a long one gives time to read the check before switching windows.

Preview width

Controlled

Pass copied and onCopiedChange to hold the copied state yourself. The button calls onCopiedChange(true) when the copy lands and onCopiedChange(false) when the check goes, so the hint below the address can follow it.

Preview width

Accessibility

The icons are hidden from assistive tech. An icon-only button needs an aria-label that says what it copies, such as Copy command. After each press, a polite status inside the button says Copied, or Couldn't copy when the clipboard refuses; change those words with copiedLabel and failedLabel.

Enter
Copy the text.
Space
Copy the text.

FAQ

What happens when the copy fails?

The icon becomes a cross for resetDelay, the status says Couldn't copy, and onCopyError gets the error. It fails when the browser denies clipboard access or the page isn't served over HTTPS, where there's no clipboard to write to.

Can I check the text before it's copied?

Yes. onCopyRequest gets the text first; return false to skip the copy, say to validate it or copy it another way. It's also the place for analytics.

Can I keep the copied state myself?

Pass copied and onCopiedChange. The button shows what copied says and asks for changes through onCopiedChange. The Controlled demo uses it for a hint below the field.

What if someone presses it again while the check shows?

It copies again and the check's timer starts over. With no content, a press does nothing.

Can it have a label and not just an icon?

Yes. Put the label in the children, such as Copy link: the icon sits before it and the size switches from icon-md to md. Pass size to choose another. Your own onClick still runs, before the copy.

What happens with reduced motion?

The icons swap with a plain fade, without scaling. The check and the cross still show.

API Reference

CopyButton

data-slot="copy-button-icon"

PropType
copied?boolean

Whether the check shows, to hold that state yourself. Pair it with onCopiedChange.

onCopiedChange?(copied: boolean) → void

Called when the check shows (true) and when it goes (false).

Parameters

copied – boolean

Returns
void
children?ReactNode

The label beside the icon; leave it out for an icon-only button.

clickEffect?boolean

Apply a click effect to the button.

Default
true
content?string

The text to copy. Without it, pressing the button does nothing.

copiedLabel?string

What screen readers hear once the text is on the clipboard.

Default
"Copied"
failedLabel?string

What screen readers hear when the clipboard refuses the text.

Default
"Couldn't copy"
isLoading?boolean

Show a loading indicator.

Default
false
onCopyError?(error: unknown) → void

Called when the clipboard refuses the text: no permission, or a page not served over HTTPS.

Parameters

error – unknown

Returns
void
onCopyRequest?(content: string) → boolean

Called with the text when a press asks to copy it. Return false to cancel the copy, after validating it or to copy it some other way.

Parameters

content – string

Returns
boolean
resetDelay?number

How long the check (or the cross, after a failed copy) stays before the copy icon comes back, in milliseconds.

Default
3000
asChild?boolean

Merge props onto the child element instead of rendering a host.

className?string

Merged with the part's classes.

AttributeType
data-state?string

Mirrors shown.