Async Loading Button

An async loading button that shows a spinner and disables itself while a promise resolves.

Installation

Adds the component and everything it depends on to your project.

npx shadcn add https://ui.beste.co/component/r-base/button3

New here? Read the installation guide.

Usage

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} />

Playground

Turn the props on the right; the snippet under them is what you would write to get what you see.

Usage
import { Button3 } from "@/components/beste/component/button3";

<Button3
  label="Create account"
  loadingLabel="Creating account..."
/>

Keyboard and gestures

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.

ClickRuns the handler. If it returns a promise the button stays busy until it settles, so a double click cannot fire it twice.
Enter / SpaceThe same: it is a real button, not a div with a handler.

Props

Read from the component's own type, so this cannot drift from what it accepts.

PropTypeDefaultDescription
label*stringButton label
loadingbooleanControlled loading state. Leave it undefined and return a promise from onClick instead, the button then manages loading by itself.
loadingLabelstringLabel shown while loading (defaults to label)
iconLucideIconOptional 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
disabledbooleanDisable independently of loading
onClick(event: React.MouseEvent<HTMLButtonElement>) => void | Promise<unknown>Click handler. Return a promise to drive the built-in loading state
classNamestringAdditional classes merged onto the button

More Button components

View all Button

Scramble Button

A scramble text button that cycles random glyphs on hover for developer and tech landings.

Hold to Confirm Button

A hold to confirm button that fills while held and fires only when the hold completes.

Letter Roll Button

A pill button whose label rolls up letter by letter with a staggered hover animation.

Avatar Stack Button

A social proof button with an avatar stack inside the pill and a trailing arrow.

Magnetic Button

A magnetic button that is pulled toward the cursor on hover and springs back on leave.

Pressable Button

A neobrutalist button with a hard offset shadow that lifts on hover and presses in on click.

Markdown version