Something new is coming.Join the waitlist

Animated Save Button

PreviousNext

React animated save button with character-by-character text animation, loading spinner, and success checkmark. Built with Framer Motion. Install with shadcn CLI.

Playground

Override each label or the simulated save duration and the snippet below updates to match.

<SaveButton onSave={handleSave} />

Props

Installation

npx shadcn@latest add https://tentui.com/r/animated-save-button.json

Usage

import { SaveButton } from "@/components/animated-save-button";
 
export default function Page() {
  const handleSave = async () => {
    await fetch("/api/save", { method: "POST" });
  };
 
  return <SaveButton onSave={handleSave} />;
}

Props

PropTypeDefaultDescription
onSave() => void | Promise<void>Called when the button is clicked. Awaited before success state.
labels{ idle?: string; loading?: string; success?: string }Override button text for each state.
classNamestringExtra classes for the outer wrapper.

How it works

Clicking transitions through idle → loading → success → idle. The onSave callback is awaited — if it throws, the component still advances to success (handle errors in your callback before rethrowing). Each state change animates the button text character by character using AnimatePresence mode="popLayout" so individual letters spring in and out independently. A badge in the top-right corner appears on state change: a spinner during loading, a check on success.

Patterns

Custom labels

<SaveButton
  labels={{ idle: "Publish", loading: "Publishing", success: "Published" }}
  onSave={handlePublish}
/>

Fire and forget (no async)

<SaveButton onSave={() => console.log("saved")} />