shadcn.io is not affiliated with official shadcn/ui
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.
Installation
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.
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.
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.
API Reference
CopyButton
data-slot="copy-button-icon"
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.
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"
focusableWhenDisabled?boolean
Whether the button should be focusable when disabled.
- Default
false
nativeButton?boolean
Whether the component renders a native <button> element when replacing it
via the render prop.
Set to false if the rendered element is not a button (for example, <div>).
- Default
true
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
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
data-state?string
Mirrors shown.
Related
- Pro
Success Button
Progress & resultsConfirm any action with a check
Loading Button
Progress & resultsShow an action while it runs
Icon Button
Hover revealsIcon-only button with an active state
Kbd Button
ControlsShow the shortcut beside the label
- Pro
Download Button
Progress & resultsProgress for files, not text
- Pro
Counter Button
ControlsAnother small state swap