A button that copies text to the clipboard, its icon swapping for a check.
Installation
Usage
import {
CopyButton,
CopyButtonIcon,
} from '@animate-ui/react/primitives/buttons/copy';
export function CopyCommand() {
return (
<CopyButton content="npx animate-ui init" aria-label="Copy">
<CopyButtonIcon icon={<CopyIcon />} copiedIcon={<CheckIcon />} />
</CopyButton>
);
}A click writes content to the clipboard (navigator.clipboard.writeText). Once it's written, the button is copied (data-copied) for delay milliseconds, then goes back. Copying again restarts the delay. Read the state in your own parts with useCopyButton().
Animation
- Once copied, the copy icon shrinks to half its size into a light blur (
blur(2px)) as it fades out, while the check grows out of the same blur in its place, over 0.15s with an ease-out (cubic-bezier(0.23, 1, 0.32, 1)). It swaps back the same way afterdelay. Nothing animates on mount. - Pressing scales the button to
tapScale(0.97), on Motion's spring for scale (stiffness: 550, damping: 30). It doesn't scale on hover, unless you sethoverScale. <AnimateUIProvider tempo>paces the swap and the press spring (notdelay).- Under reduced motion, the icons crossfade through their blur without scaling, and the button doesn't scale.
API Reference
CopyButton
| Prop | Type | Default |
|---|---|---|
content | string | - |
copied? | boolean | - |
defaultCopied? | boolean | false |
onCopiedChange? | (copied: boolean, content?: string) => void | - |
delay? | number | 3000 |
hoverScale? | number | 1 |
tapScale? | number | 0.97 |
transition? | Transition | { type: 'spring', stiffness: 550, damping: 30, restSpeed: 10 } |
asChild? | boolean | false |
...props? | HTMLMotionProps<'button'> | - |
CopyButtonIcon
| Prop | Type | Default |
|---|---|---|
icon | React.ReactNode | - |
copiedIcon | React.ReactNode | - |
transition? | Transition | { duration: 0.15, ease: [0.23, 1, 0.32, 1] } |
...props? | React.ComponentProps<'span'> | - |
Data attributes
| Prop | Type | Default |
|---|---|---|
data-copied? | present | - |