Docs

Status Button

A button that transitions the status change. Click to see the animation.

requires interactionclick

Installation

Install dependencies

npm install framer-motion lucide-react

Run the following command

It will create a new file status-button.tsx inside the components/animata/button directory.

mkdir -p components/animata/button && touch components/animata/button/status-button.tsx

Paste the code

Open the newly created file and paste the following code:

import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { CheckCircle2, CircleDashed } from "lucide-react";
 
import { cn } from "@/lib/utils";
 
const wait = async (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
 
export default function StatusButton() {
  const [status, setStatus] = useState<"loading" | "Add to cart" | "Added to cart">();
  const isEnabled = !status || status === "Add to cart";
 
  const changeStatus = async () => {
    if (!isEnabled) {
      return;
    }
 
    setStatus("loading");
    await wait(1500);
    setStatus("Added to cart");
    await wait(1500);
    setStatus("Add to cart");
  };
 
  return (
    <button
      onClick={changeStatus}
      disabled={!isEnabled}
      className="group relative h-10 min-w-40 overflow-hidden rounded-md bg-teal-500 px-6 text-sm font-semibold text-white transition-colors duration-300 hover:bg-teal-600"
    >
      <AnimatePresence mode="wait" initial={false}>
        <motion.span
          // Remount the component so that the animation can be restarted
          key={status}
          initial={{ opacity: 0, y: -15 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: 15 }}
          transition={{ duration: 0.075 }}
          className={cn("flex items-center justify-center gap-1")}
        >
          {status === "Added to cart" && (
            <motion.span
              className="h-fit w-fit"
              initial={{ scale: 0 }}
              animate={{ scale: 1 }}
              transition={{ delay: 0.075, type: "spring" }}
            >
              <CheckCircle2 className="h-4 w-4 fill-white stroke-teal-500 group-hover:stroke-teal-600" />
            </motion.span>
          )}
 
          {status == "loading" ? (
            <CircleDashed className="h-4 w-4 animate-spin" />
          ) : (
            status ?? "Add to cart"
          )}
        </motion.span>
      </AnimatePresence>
    </button>
  );
}

Credits

Built by hari

Inspired by https://animations.dev/gallery