Async button

Inspect

The button for anything that runs an action: saving, sending, paying, deleting. It runs submitAction in its own transition, swaps the label for a spinner in place, then shows how it went. The caller keeps no pending state (no isLoading, no useTransition); it only returns the outcome. The one above succeeds and fails in turn, so press it twice.

Examples

Success

Returning "success" draws a check beside successLabel for a moment before the button settles. Use it where the result would otherwise be invisible, like a copied link.

Inspect

Error

The caller says what went wrong (a toast), then returns "error". The button shakes, draws a cross beside errorLabel, and offers to try again a moment later.

Inspect

Pending label

A wait long enough that a bare spinner reads as stuck gets a word beside it. Returning nothing means done with nothing to show, usually because a navigation follows.

Inspect

Confirm

confirm asks first: the button opens an alert dialog and its "Yes" runs the action. The dialog stays open while the action runs, closes when it lands, and stays open on "error" so "Yes" can shake and be pressed again; Enter confirms. It fails every other time here.

Inspect

API reference

Every Button prop applies too; with confirm they style the trigger.

PropTypeDefaultDescription
submitAction() => "success" | "error" | undefined | Promise<"success" | "error" | undefined | void>—Runs in the button's own transition. Say what went wrong yourself before returning "error".
successLabelReactNode—Shown with a check after "success". Defaults to the label.
errorLabelReactNode—Shown with a cross after "error". Defaults to the label.
pendingLabelReactNode—Shown beside the spinner, for a wait long enough that a spinner alone reads as stuck.
hideIconbooleanfalseText only, no check or cross.
loadingbooleanfalseShows the spinner for work the button doesn't run itself, like a form submitting.
confirm{ title?: ReactNode; description: ReactNode; className?: string }—Ask first. The title defaults to "Are you sure?"; className sizes the dialog.