An async loading button that shows a spinner and disables itself while a promise resolves.
Adds the component and everything it depends on to your project.
npx shadcn add https://ui.beste.co/component/r-base/button3New here? Read the installation guide.
The import and the props worth knowing about, in one place.
import { Button3 } from "@/components/beste/component/button3";
// Return a promise from onClick and the button handles loading itself:
// spinner + loadingLabel + disabled until the promise settles.
<Button3
label="Create account"
loadingLabel="Creating account..."
tone="primary" // "dark" (default) | "primary" | "outline"
type="submit" // "button" (default) | "submit"
onClick={async () => {
await new Promise((resolve) => setTimeout(resolve, 2000));
console.log("account created");
}}
/>
// Or drive it yourself with your own state:
// <Button3 label="Save changes" loading={isSaving} />Turn the props on the right; the snippet under them is what you would write to get what you see.
import { Button3 } from "@/components/beste/component/button3";
<Button3
label="Create account"
loadingLabel="Creating account..."
/>Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Click | Runs the handler. If it returns a promise the button stays busy until it settles, so a double click cannot fire it twice. |
|---|---|
| Enter / Space | The same: it is a real button, not a div with a handler. |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
label* | string | — | Button label |
loading | boolean | — | Controlled loading state. Leave it undefined and return a promise from onClick instead, the button then manages loading by itself. |
loadingLabel | string | — | Label shown while loading (defaults to label) |
icon | LucideIcon | — | Optional leading icon (replaced by the spinner while loading) |
tone | "dark" | "primary" | "outline" | — | Surface tone: solid dark (default), primary, or bordered outline |
type | "button" | "submit" | — | HTML button type, use "submit" inside forms |
disabled | boolean | — | Disable independently of loading |
onClick | (event: React.MouseEvent<HTMLButtonElement>) => void | Promise<unknown> | — | Click handler. Return a promise to drive the built-in loading state |
className | string | — | Additional classes merged onto the button |
A scramble text button that cycles random glyphs on hover for developer and tech landings.
A hold to confirm button that fills while held and fires only when the hold completes.
A pill button whose label rolls up letter by letter with a staggered hover animation.