Morphs from idle to loading to success and back. The width animates to fit each label and the check draws itself. Driven by a promise returned from onClick or by a status prop.
npx shadcn@latest add https://hyperblur.dev/r/button-stateful.jsonWorks in any React project set up with the shadcn CLI. The file lands in components/hyperblur/button-stateful.tsx.
import { ButtonStateful } from "@/components/hyperblur/button-stateful"
<ButtonStateful onClick={() => save()} loadingLabel="Saving" successLabel="Saved">Save changes</ButtonStateful>| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | "Save changes" | Button label. |
| onClick | (event) => unknown | Click handler. When it returns a promise the button stays loading until it settles, then shows success. A rejection returns it to idle. | |
| status | "idle" | "loading" | "success" | Controlled status. When set, the button no longer manages its own state. | |
| loadingLabel | ReactNode | "Saving" | Label next to the spinner. |
| successLabel | ReactNode | "Saved" | Label next to the check. |
| duration | number | 1500 | Loading time in milliseconds when onClick does not return a promise. |
| resetAfter | number | 1800 | Milliseconds the success state stays before returning to idle. |
| variant | "solid" | "outline" | "solid" | Accent filled button or a bordered transparent button. |
| accent | string | "#2f7bff" | Accent color used for the focus ring, highlights and the solid variant. |
| successAccent | string | "#22c55e" | Color of the success state. |
| size | "sm" | "md" | "lg" | "md" | Font size and padding preset. |
| disabled | boolean | false | Disables the button and dims it. |