Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Copy Text for React

Text that copies itself when pressed: it slides away as Copied rises in its place, then comes back. For React with Base UI, when a command, a key or a link should go to the clipboard in one press.

Framework

Copy Text is a piece of text you press to copy: it goes to the clipboard, the text slides up out of sight as Copied rises in its place and the copy icon turns into a check, then after two seconds the text comes back. If the clipboard refuses, it says so instead.

Use it for an install command, an API key, an order number or a share link set inline, where the text itself is the button. For a copy icon beside a field or a code block, use Copy Button; to hide a secret until it's asked for, Password Text. It wraps the Button, so variant and size work as usual; the state is one data attribute that CSS transitions draw, with no animation library, and with reduced motion the labels only fade.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import { CopyText } from "@/components/ui/copy-text";
<CopyText className="font-mono" text="npx shadcn@latest add button" />

Demos

Content

content is what goes on the clipboard when it isn't the text shown: a whole key behind a shortened one, a full link behind a short one. Give each an aria-label that says what it copies.

Preview width

Variant

It's a Button underneath, ghost and sm by default, so any variant and size work. copiedLabel is the word that takes the text's place, Copied by default.

Preview width

Accessibility

It's a real button, named by its text, or by an aria-label when you give one. The sliding labels and the icons are hidden from assistive tech; a polite status inside the button says Copied, or Couldn't copy when the clipboard refuses. Change those words with copiedLabel and failedLabel, which also show on screen. With reduced motion the labels cross-fade without sliding.

Enter
Copy the text.
Space
Copy the text.

FAQ

Why is there space around a short text?

The text and the labels share one place, and the widest sets its width, so the button never changes size as they swap. Keep copiedLabel and failedLabel about as long as the text, or shorter.

What happens when the copy fails?

Couldn't copy takes the text's place with a cross, for resetDelay, and the status says it. The clipboard refuses when the browser denies access or the page isn't served over HTTPS.

What if someone presses it again while it says Copied?

It copies again and the timer starts over, so the label doesn't flicker back to the text in between.

How do I know it was copied?

onCopiedChange is called with true when the text reaches the clipboard and false when the text comes back. Use it for analytics, or to show a hint elsewhere.

What about a long text?

It stays on one line and ends with an ellipsis where its container runs out, while the whole of it is still copied. Keep it short enough to read: a command, a key, a link.

What happens with reduced motion?

The text and Copied cross-fade in place, without sliding, and the icons swap without scaling.

API Reference

CopyText

data-slot="copy-text-label"

PropType
textstring

The text shown, and copied unless content says otherwise.

content?string

What goes on the clipboard when it isn't the text itself, such as a whole key behind a shortened one.

Default
text
copiedLabel?string

What shows in place of the text once it's copied, and what screen readers hear.

Default
"Copied"
failedLabel?string

What shows, and 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
onCopiedChange?(copied: boolean) → void

Called when the copied state starts (true) and when it ends (false).

Parameters

copied – boolean

Returns
void
resetDelay?number

How long the copied (or failed) state stays before the text comes back, in milliseconds.

Default
2000
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.

AttributeType
data-state?string

Mirrors status.

All 97 text effects