Copy Button

A button that copies text to the clipboard.

npx shadcn@latest add @shuip/copy-button
pnpm dlx shadcn@latest add @shuip/copy-button
bun x shadcn@latest add @shuip/copy-button
'use client';

import { CheckIcon, Copy } from 'lucide-react';
import * as React from 'react';
import { Button } from '@/components/ui/button';

const DEFAULT_TIMEOUT = 2000;

export interface CopyButtonProps extends React.ComponentProps<typeof Button> {
  value: string;
  copiedIcon?: React.ReactNode;
  notCopiedIcon?: React.ReactNode;
}

export function CopyButton({ value, copiedIcon = <CheckIcon />, notCopiedIcon = <Copy />, ...props }: CopyButtonProps) {
  const [hasCopied, setHasCopied] = React.useState(false);

  const handleCopy = () => {
    navigator.clipboard.writeText(value);
    setHasCopied(true);
    setTimeout(() => {
      setHasCopied(false);
    }, DEFAULT_TIMEOUT);
  };

  return (
    <Button size='icon' variant={'ghost'} className={'z-10 size-4'} onClick={handleCopy} {...props}>
      <span className='sr-only'>Copy</span>
      {hasCopied ? copiedIcon : notCopiedIcon}
    </Button>
  );
}

The command is the same for Base UI and Radix: the CLI reads the style in your components.json and installs the matching variant.

Loading...

Examples

Default

Loading...
'use client';

import { CopyButton } from '@/components/ui/shuip/copy-button';

export default function CopyButtonExample() {
  return <CopyButton value='Hello, world!' />;
}

With Custom Icons

Loading...
'use client';

import { Cat, Dog } from 'lucide-react';
import { CopyButton } from '@/components/ui/shuip/copy-button';

export default function CopyButtonWithCustomIconsExample() {
  return (
    <CopyButton
      value='Hello, cat!'
      copiedIcon={<Dog className='size-6' />}
      notCopiedIcon={<Cat className='size-6' />}
      className='size-8'
      variant={'default'}
    />
  );
}

Props

Prop

Type

On this page