Toast

Animated toast notification for copying an API key: click “Copy” to copy the key, triggers a smooth floating “Copied” toast, then fades out automatically inspired by dmytro.

Loading demo...

default.tsx
"use client";
 
import { cn, TRANSITION } from "@/lib/utils";
import { AlertCircleIcon } from "@hugeicons/core-free-icons";
import { HugeiconsIcon } from "@hugeicons/react";
import { AnimatePresence, motion, MotionConfig } from "motion/react";
import { useRef, useState } from "react";
import { buttonVariants } from "@/components/ui/button";
 
const variant = {
  show: {
    opacity: 1,
    y: -85,
    filter: "blur(0px)",
  },
  hidden: {
    y: -40,
    opacity: 0,
    filter: "blur(4px)",
  },
};
 
const BetterToast = () => {
  const key = "sk_live_••••••••••••••••••";
  const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const [isActive, setIsActive] = useState(false);
 
  const handleCopy = async () => {
    await navigator.clipboard.writeText(key);
 
    setIsActive(true);
 
    if (timeoutRef.current) clearTimeout(timeoutRef.current);
 
    timeoutRef.current = setTimeout(() => {
      setIsActive(false);
    }, 1600);
  };
 
  return (
    <MotionConfig transition={TRANSITION}>
      <div className="size-full flex items-center justify-center bg-background">
        <div className="max-w-lg w-full mx-auto p-1  rounded-xl border border-border/25 bg-muted">
          <div className="max-w-lg w-full mx-auto border border-border bg-background rounded-lg p-4 flex flex-col gap-4">
            <div>
              <h1 className="font-semibold text-xl">API Key</h1>
              <p className="text-muted-foreground">Start building today</p>
            </div>
            <div className="flex flex-col items-end gap-2">
              <div className="w-full relative z-0">
                <div className="border p-2 rounded-xl flex items-center justify-between z-20 bg-background">
                  <span>{key}</span>
                  <button
                    onClick={handleCopy}
                    className={cn(
                      buttonVariants({ variant: "outline" }),
                      "bg-muted opacity-100 transition duration-300",
                      {
                        "opacity-0": isActive,
                      },
                    )}
                  >
                    Copy
                  </button>
                </div>
                <AnimatePresence>
                  {isActive && (
                    <motion.div
                      variants={variant}
                      initial="hidden"
                      animate="show"
                      exit="hidden"
                      className="border border-blue-500 w-fit rounded bg-blue-50 text-blue-500 px-2 py-0.5 font-medium absolute right-2 text-sm -z-10"
                    >
                      Copied
                    </motion.div>
                  )}
                </AnimatePresence>
              </div>
              <p className="text-muted-foreground flex items-center gap-2 w-fit text-sm">
                <HugeiconsIcon icon={AlertCircleIcon} className="size-4" />
                <span>Need another API Key?</span>
              </p>
            </div>
          </div>
        </div>
      </div>
    </MotionConfig>
  );
};
 
export default BetterToast;