Copy Button
Copy a value to the clipboard with transient check feedback — built on Button.
- Status
- Since
0.1.0- Accessibility pattern
- native button + status announcement
Last updated
npx shadcn add @vegastack/buttonInstall
Add Copy Button from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.
pnpm dlx shadcn@latest add @vegastack/copy-buttonThe same command installs the registry items it composes: @vegastack/button, @vegastack/icon-button, @vegastack/use-announcer.
Usage
import { CopyButton } from "@/components/ui/copy-button";
<CopyButton value="npx shadcn add @vegastack/button" />;Examples
Copy feedback
A ghost / sm icon button that writes value to the clipboard and swaps the
Copy icon for a Check for ~1.5s. Pair it with the value it copies — an API
key, an invite link, a code snippet — and use onCopied to surface a toast.
npx shadcn add @vegastack/buttonVisible label
Set showLabel when the action needs stronger discoverability. The current
copyLabel or copiedLabel appears beside the icon, and the control switches from an
IconButton (square, sm) to a text-bearing Button at the same size.
With a toast
onCopied fires after a successful clipboard write — use it to confirm the action
with a toast or to log an analytics event. The transient check feedback is handled
internally, so onCopied is purely for your side effects.
vsk_live_3f9a…<CopyButton value={apiKey} onCopied={() => toast.success("API key copied")} />States
Idle shows the Copy icon. After a successful copy the icon swaps to a Check
tinted text-primary and the accessible label flips from Copy to Copied
for timeout ms (default 1500), with data-copied set for that window. disabled
is forwarded straight to the underlying button. The copied state is owned internally
and only appears after a real write, so the middle cell below is live — click it.
Variants
CopyButton defaults to variant="ghost" but forwards the whole
Button variant × tone matrix unchanged.
Sizes
size is forwarded too, from the one xs · sm · md · lg vocabulary. It defaults to sm.
An explicit size always wins.
Playground
Try the forwarded variant × tone and size axes, the label toggle, and the disabled state — the
copy action is live — then copy the generated JSX.
<CopyButton value="pnpm dlx shadcn@latest add @vegastack/button" />API Reference
CopyButton forwards supported Button presentation props
(variant, size, className, disabled, …) and owns the clipboard action, button
type, accessible labels, and icon children.
| Prop | Type | Default | Description |
|---|---|---|---|
value* | string | — | The text written to the clipboard when the button is pressed. |
className | string | ((state: ButtonState) => string | undefined) | — | Classes or a Base UI state resolver merged with the button variants. |
copiedLabel | string | 'Copied' | Accessible label while the copied confirmation is visible. |
copyLabel | string | 'Copy' | Accessible label before the value has been copied. |
data-loading | string | — | Loading-state marker for wrapper components that reflect a host-owned pending
state onto a composed Button without its loading visuals (e.g. SplitButton's
chevron half). The Button's own loading prop always wins when set. |
data-slot | string | 'button' | Slot marker for wrapper components that compose Button through Base UI
render and need their own generated registry slot. |
loading | boolean | false | Shows a spinner over the label, disables interaction, and sets aria-busy. The
label keeps its box at opacity: 0, so the button's width does not move across
the flip and its accessible name survives. |
onCopied | ((value: string) => void) | — | Fired after value is successfully copied to the clipboard. Use it to show a
toast or analytics event — the transient check feedback is handled internally. |
onPress | ((event: React.MouseEvent<HTMLElement>) => void) | — | Called when the copy button is pressed before the clipboard write runs.
Calling event.preventDefault() cancels the write. |
showLabel | boolean | false | Show the current copy status as visible text beside the icon. With a label the control is a
text Button; without one it is an IconButton. An explicit size still wins. |
size | ButtonSize | 'md' | Control height, from the one xs · sm · md · lg vocabulary the --size-* tokens carry. |
timeout | number | 1500 | How long (in milliseconds) the check icon stays visible before reverting to the copy icon. |
tone | ButtonTone | — | |
variant | "cta" | "ghost" | "link" | "outline" | "soft" | "solid" | — |
Data attributes and CSS variables on CopyButton
| Attribute | Values |
|---|---|
data-slot | "copy-button-label" |
Accessibility
- Renders a native
<button type="button">; keyboard Enter / Space activate it. - The accessible name switches from
CopytoCopiedon success so screen readers announce the result; the icon is decorative (aria-hidden). - Inherits the underlying
Button's focus treatment: the defaultghostvariant shows the design system's global 2px focus ring (outline-ring) on:focus-visibleand never setsoutline: none. The borderedoutlinevariant additionally re-colors its border with theringtoken (focus-visible:border-ring/(--alpha-tint-border)). - A failed clipboard write (denied permission or insecure context) leaves the button in its default state instead of showing a false success.
| Key | Action |
|---|---|
| Tab | Move focus to the button. |
| Enter / Space | Copy value to the clipboard. |
| Contract | States tested |
|---|---|
| Behaviour | default, copied, empty, pressed, success |
| Accessibility | labeled, status-announcement |
| Visual | default, hover, success, empty |