All Components

Copy Email Button

we'll create a beautiful and interactive copy email button component using Next.js, Framer Motion, and Tailwind CSS. This component features smooth animations and state transitions that make it both functional and visually appealing.

What We'll Build

The Copy Email Button component has three main states:

  1. Default State: Shows the email address with a mail icon
  2. Hover State: Displays a copy icon when the user hovers over the button
  3. Copied State: Shows a success message with a checkmark when the email is copied

First, let's install the necessary packages. We'll need:

  • Framer Motion for animations
  • Lucide React for icons
  • Tailwind Merge for combining Tailwind classes
npm install framer-motion

And also:

npm install lucide-react

npm install tailwind-merge

Full Implementation Details

"use client";
import React, { useState } from "react";
import { Copy, Mail, SquareCheck } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";
import { twMerge } from "tailwind-merge";

const CopyEmailButton = () => {
const [buttonState, setButtonState] = useState<"hover" | "copy" | "default">(
  "default"
);

const handleCopy = async () => {
  try {
    await navigator.clipboard.writeText("hi@omarcode.me");
    setButtonState("copy");
    setTimeout(() => setButtonState("default"), 2000); // Reset after 2 seconds
  } catch (err) {
    console.error("Failed to copy:", err);
  }
};

return (
  <button
    className={twMerge(
      "w-full max-w-[210px] bg-gradient-to-br to-50% to-neutral-900 p-px rounded-xl overflow-hidden",
      buttonState === "copy"
        ? "from-[#f77f5e]"
        : "from-gray-400 hover:from-white"
    )}
    onMouseEnter={() => buttonState !== "copy" && setButtonState("hover")}
    onMouseLeave={() => buttonState !== "copy" && setButtonState("default")}
    onClick={handleCopy}
  >
    <div className="text-white bg-gradient-to-br from-neutral-900 from-35% to-white/10 px-4 py-2.5 md:py-3 rounded-[11px]">
      <AnimatePresence initial={false} mode="wait">
        {buttonState === "copy" ? (
          <motion.div
            key="copied"
            initial={{ y: 40 }}
            animate={{ y: 0 }}
            exit={{ y: 40 }}
            transition={{ duration: 0.2 }}
            className="flex justify-center items-center space-x-2"
          >
            <p className="text-sm md:text-base font-medium">Copied</p>
            <SquareCheck size={20} />
          </motion.div>
        ) : (
          <motion.div
            key="copy-mail"
            initial={{ y: -40 }}
            animate={{ y: 0 }}
            exit={{ y: -40 }}
            transition={{ duration: 0.2 }}
            className="flex justify-center items-center"
          >
            <AnimatePresence initial={false}>
              {buttonState === "default" && (
                <motion.div
                  key="mail"
                  initial={{ x: -80, width: 0 }}
                  animate={{ x: 0, width: 20 }}
                  exit={{ x: -80, width: 0 }}
                  transition={{ duration: 0.4 }}
                >
                  <Mail size={20} />
                </motion.div>
              )}
            </AnimatePresence>
            <p className="text-sm md:text-base font-medium px-2">
              hi@omarcode.me
            </p>
            <AnimatePresence>
              {buttonState === "hover" && (
                <motion.div
                  key="copy"
                  initial={{ x: 80, width: 0 }}
                  animate={{ x: 0, width: 20 }}
                  exit={{ x: 80, width: 0 }}
                  transition={{ duration: 0.4 }}
                >
                  <Copy size={20} />
                </motion.div>
              )}
            </AnimatePresence>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  </button>
);
};

export default CopyEmailButton;

Happy Coding 👋

Want to Learn How to Build These Components Yourself?

We have step-by-step tutorials for every component to help you create stunning interfaces with ease.

Tutorials on YouTube