Async button

Wraps any async action and manages idle, loading, success, and error states automatically. Spring physics on every transition — no linear easing.

Live demo

Why it animates

Users triggering async actions need unambiguous feedback before the server responds. The spring transition to the loading state signals 'I received your action' immediately, reducing repeat submissions and uncertainty.

Usage
import { AsyncButton } from '@/components/ui/AsyncButton'

// Automatically handles loading, success, and error states.
// Pass any async function — the component does the rest.

async function handleSave() {
  await api.save(formData)
}

<AsyncButton onClick={handleSave}>
  Save changes
</AsyncButton>