Docs
Creative Clipboard Actions

Creative Clipboard Actions

A modern and animated clipboard actions component with multiple variants and styles.

Variants

default
minimal
floating
gradient
outline

Sizes

sm
md
lg

Installation

Copy and paste the following code into your project.

components/ui/creative-clipboard-actions.tsx

"use client";
 
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { cn } from "@/lib/utils";
import { Check, Copy, Link, ClipboardCheck, ClipboardCopy } from "lucide-react";
 
type Variant = "default" | "minimal" | "floating" | "gradient" | "outline";
type Size = "sm" | "md" | "lg";
 
interface CreativeClipboardActionsProps {
  text: string;
  variant?: Variant;
  size?: Size;
  className?: string;
  showLink?: boolean;
  onCopy?: () => void;
}
 
const variants = {
  default: {
    button: {
      base: "rounded-lg border transition-all duration-200",
      idle: "border-muted-foreground/20 dark:border-muted-foreground/10 bg-background dark:bg-background/80 hover:bg-muted/80 dark:hover:bg-muted/20",
      copied:
        "border-green-500/50 dark:border-green-400/30 bg-green-50 dark:bg-green-950/30 text-green-600 dark:text-green-400",
    },
    icon: {
      idle: "text-muted-foreground dark:text-muted-foreground/80",
      copied: "text-green-600 dark:text-green-400",
    },
  },
  minimal: {
    button: {
      base: "rounded-md transition-all duration-200",
      idle: "hover:bg-muted/80 dark:hover:bg-muted/20",
      copied: "text-green-600 dark:text-green-400",
    },
    icon: {
      idle: "text-muted-foreground dark:text-muted-foreground/80",
      copied: "text-green-600 dark:text-green-400",
    },
  },
  floating: {
    button: {
      base: "rounded-full shadow-lg transition-all duration-300",
      idle: "bg-background dark:bg-background/90 hover:shadow-xl hover:-translate-y-0.5",
      copied:
        "bg-green-50 dark:bg-green-950/30 text-green-600 dark:text-green-400 shadow-green-500/20 dark:shadow-green-400/20",
    },
    icon: {
      idle: "text-muted-foreground dark:text-muted-foreground/80",
      copied: "text-green-600 dark:text-green-400",
    },
  },
  gradient: {
    button: {
      base: "rounded-lg transition-all duration-300 bg-linear-to-r",
      idle: "from-primary/10 to-primary-foreground/10 dark:from-primary/20 dark:to-primary-foreground/20 hover:from-primary/20 hover:to-primary-foreground/20 dark:hover:from-primary/30 dark:hover:to-primary-foreground/30",
      copied:
        "from-green-500/20 to-green-400/20 dark:from-green-500/30 dark:to-green-400/30",
    },
    icon: {
      idle: "text-primary dark:text-primary/90",
      copied: "text-green-600 dark:text-green-400",
    },
  },
  outline: {
    button: {
      base: "rounded-lg border-2 transition-all duration-200",
      idle: "border-primary/50 dark:border-primary/30 hover:border-primary dark:hover:border-primary/50",
      copied: "border-green-500/50 dark:border-green-400/30",
    },
    icon: {
      idle: "text-primary dark:text-primary/90",
      copied: "text-green-600 dark:text-green-400",
    },
  },
};
 
const sizes = {
  sm: {
    button: "p-2",
    icon: "h-4 w-4",
  },
  md: {
    button: "p-3",
    icon: "h-5 w-5",
  },
  lg: {
    button: "p-4",
    icon: "h-6 w-6",
  },
};
 
export function CreativeClipboardActions({
  text,
  variant = "default",
  size = "md",
  className,
  showLink = false,
  onCopy,
}: CreativeClipboardActionsProps) {
  const [copied, setCopied] = useState(false);
  const [isHovered, setIsHovered] = useState(false);
 
  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(text);
      setCopied(true);
      onCopy?.();
 
      setTimeout(() => {
        setCopied(false);
      }, 2000);
    } catch (err) {
      console.error("Failed to copy text:", err);
    }
  };
 
  const IconComponent = showLink
    ? copied
      ? Check
      : Link
    : copied
      ? ClipboardCheck
      : ClipboardCopy;
 
  return (
    <motion.button
      onClick={handleCopy}
      onHoverStart={() => setIsHovered(true)}
      onHoverEnd={() => setIsHovered(false)}
      className={cn(
        variants[variant].button.base,
        variants[variant].button[copied ? "copied" : "idle"],
        sizes[size].button,
        className,
      )}
      whileHover={{ scale: 1.05 }}
      whileTap={{ scale: 0.95 }}
    >
      <AnimatePresence mode="wait">
        <motion.div
          key={copied ? "copied" : "idle"}
          initial={{ opacity: 0, y: 10 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: -10 }}
          className="relative"
        >
          <IconComponent
            className={cn(
              variants[variant].icon[copied ? "copied" : "idle"],
              sizes[size].icon,
            )}
          />
          {variant !== "minimal" && isHovered && !copied && (
            <motion.div
              initial={{ opacity: 0, scale: 0.8 }}
              animate={{ opacity: 1, scale: 1 }}
              className="absolute -right-1 -top-8 whitespace-nowrap rounded-md bg-foreground/90 px-2 py-1 text-xs text-background dark:bg-background/90 dark:text-foreground"
            >
              {showLink ? "Copy Link" : "Copy"}
            </motion.div>
          )}
        </motion.div>
      </AnimatePresence>
    </motion.button>
  );
}

Update the import paths to match your project setup.

import { CreativeClipboardActions } from "@/components/ui/creative-clipboard-actions";

Examples

Default Clipboard Action

<CreativeClipboardActions text="Text to copy" />
<CreativeClipboardActions
  text="https://example.com"
  showLink
  variant="minimal"
/>

Floating Style

<CreativeClipboardActions text="Copy me!" variant="floating" size="lg" />

Gradient Style

<CreativeClipboardActions text="Gradient style" variant="gradient" />

Inside Card

<div className="flex items-center gap-2 rounded-lg border bg-card p-4">
  <span className="text-sm">npm install ui</span>
  <CreativeClipboardActions text="npm install ui" variant="minimal" />
</div>

Props

PropTypeDefaultDescription
textstring-Text to copy to clipboard
variant"default" | "minimal" | "floating" | "gradient" | "outline""default"Visual style variant
size"sm" | "md" | "lg""md"Size of the button
showLinkbooleanfalseShow link icon instead of clipboard
classNamestring-Additional CSS classes
onCopy() => void-Callback when text is copied