Componentform0.86 KB gzipZero dependencies

Copy Button

Tactile button with clipboard feedback and check state.

Preview

Live Preview
npm install bigbullui

Installation

Tokens guide →

Add to your project via CLI (zero dependencies, code you own):

npx bigbullui add copy-button

Or install the full npm package:

npm install bigbullui
import { CopyButton } from "@/components/ui/copy-button";

<CopyButton value="npm install bigbullui" />

Usage guidance

Use Copy Button when a ticket stub surface needs Tactile button with clipboard feedback and check state. Keep props minimal and prefer composition with sibling stubs.

Avoid Copy Button for long form flows or dense data grids where a dedicated layout block fits better.

Source code

copy-button.tsx

Zero dependencies (only React + utils). Copy and paste directly into your project:

"use client";

import * as React from "react";
import { cn } from "./lib/utils";

export interface CopyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  value: string;
  timeout?: number;
  className?: string;
}

export function CopyButton({
  value,
  timeout = 2000,
  className,
  ...props
}: CopyButtonProps) {
  const [copied, setCopied] = React.useState(false);

  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(value);
      setCopied(true);
      setTimeout(() => setCopied(false), timeout);
    } catch {
      // fallback
    }
  };

  return (
    <button
      type="button"
      onClick={handleCopy}
      aria-label={copied ? "Copied" : "Copy to clipboard"}
      className={cn(
        "inline-flex cursor-pointer items-center gap-1.5 rounded-sm border border-dashed border-border bg-secondary px-2 py-1 font-mono text-[11px] font-medium text-secondary-foreground transition-all duration-150 active:scale-95",
        "hover:border-foreground/50 hover:bg-card focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
        copied && "border-accent text-accent",
        className
      )}
      {...props}
    >
      {copied ? (
        <>
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <polyline points="20 6 9 17 4 12" />
          </svg>
          <span>COPIED</span>
        </>
      ) : (
        <>
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
            <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
          </svg>
          <span>COPY</span>
        </>
      )}
    </button>
  );
}

Props

PropTypeDescription
valuestring
timeout?number
className?string