React + MotionButtons

Lade-Button mit Erfolg

Nach dem Klick wird der Text zum Spinner und dann zu einem Häkchen, bevor der Button wieder zurückspringt.

Einstellungen

24px
1

Code

import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Check, Loader2 } from "lucide-react";

interface LoadingButtonProps {
  color?: string;
  radius?: number;
  text?: string;
  /** Multiplica la velocidad de la carga simulada. */
  intensity?: number;
}

export default function LoadingButton({
  color = "#0071e3",
  radius = 24,
  text = "Änderungen speichern",
  intensity = 1,
}: LoadingButtonProps) {
  const [state, setState] = useState<"idle" | "loading" | "success">("idle");

  return (
    <motion.button
      type="button"
      className="flex min-w-36 items-center justify-center gap-2 px-6 py-3 text-sm font-semibold text-white shadow-lg"
      style={{
        backgroundColor: state === "success" ? "#0071e3" : color,
        borderRadius: radius,
      }}
      animate={{ scale: state === "loading" ? 0.97 : 1 }}
      onClick={() => {
        if (state !== "idle") return;
        setState("loading");
        setTimeout(() => setState("success"), 1500 / intensity);
        setTimeout(() => setState("idle"), 1500 / intensity + 1800);
      }}
    >
      <AnimatePresence mode="wait" initial={false}>
        {state === "idle" && (
          <motion.span
            key="idle"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
          >
            {text}
          </motion.span>
        )}
        {state === "loading" && (
          <motion.span
            key="loading"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
          >
            <Loader2 className="h-4 w-4 animate-spin" />
          </motion.span>
        )}
        {state === "success" && (
          <motion.span
            key="success"
            initial={{ opacity: 0, scale: 0.5 }}
            animate={{ opacity: 1, scale: 1 }}
            exit={{ opacity: 0 }}
            className="flex items-center gap-1.5"
          >
            <Check className="h-4 w-4" /> Fertig
          </motion.span>
        )}
      </AnimatePresence>
    </motion.button>
  );
}

Prompt für KI

Füg ihn in ChatGPT, Claude oder Cursor ein und der Baustein wird mit diesen Einstellungen an dein Projekt angepasst, auch ohne React.

Mehr aus Buttons

Wofür du ihn nutzen kannst

Wenn scheinbar nichts passiert, klicken Leute ein zweites Mal. Dieser Button reagiert sofort: Er zeigt, dass er arbeitet, und bestätigt dann. Gut für „Änderungen speichern“ in den Einstellungen, „Nachricht senden“ im Kontaktformular oder „Gutschein einlösen“ im Checkout. Bereit, lädt, fertig: Diese drei Zustände braucht fast jedes Formular von einem Lade-Button.

In der Demo ist die Wartezeit nur simuliert, verknüpf den Erfolg also mit deiner echten Anfrage. Kann das Speichern schiefgehen, bau auch einen Fehlerzustand ein. Ein Häkchen, obwohl nichts gespeichert wurde, ist schlimmer als gar keine Animation.