Xzero UI
Pro library

Confirm morph

A destructive button that morphs into an inline confirmation, a spinner, and a result with undo.

$ pnpm dlx shadcn@4.23.0 add @xzero-ui/confirm-morph
Live · keyboard ready

When to use

When not to use

Installation

Register both Xzero UI namespaces in your project's components.json:

{
  "registries": {
    "@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
    "@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
  }
}
npx shadcn@4.23.0 add @xzero-ui/confirm-morph

Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.

Usage

import { Trash2 } from "lucide-react";
import { ConfirmMorph } from "@/components/xzero/confirm-morph/confirm-morph";

export function DeleteSelection({ ids }: { ids: string[] }) {
  return (
    <ConfirmMorph
      label="Delete files"
      icon={<Trash2 size={16} strokeWidth={1.75} />}
      prompt={`Delete ${ids.length} files?`}
      confirmMode="hold"
      onConfirm={() => deleteFiles(ids)}
      onUndo={() => restoreFiles(ids)}
    />
  );
}

API reference

ConfirmMorph

A button for destructive or important actions that morphs in place into an inline question, then a spinner, then a result with Undo. Answer it with a click, a press and hold, or a click and a short countdown.

PropTypeDefaultDescription
label (required)ReactNode–The resting label, such as "Delete project".
iconReactNode–A plain icon before the resting label.
promptReactNode–The question while confirming, such as "Delete 3 files?". Defaults to the label with a question mark.
confirmLabelstring"Delete"Confirm button label.
cancelLabelstring"Cancel"Cancel button label.
pendingLabelstring"Deleting"Shown beside the spinner while onConfirm resolves.
doneLabelstring"Deleted"Result label.
errorLabelstring"Couldn’t finish"Error label.
retryLabelstring"Retry"Retry button label on the error face.
undoLabelstring"Undo"Undo button label.
undoingLabelstring"Restoring"Shown beside the spinner while onUndo resolves.
tone"danger" | "neutral""danger"danger gives the confirm button the danger colour, for actions that destroy something; neutral gives it the accent, for important actions that can be reversed. The resting button is neutral either way.
confirmMode"press" | "hold" | "countdown""press"press confirms on a press. hold asks for the confirm button to be held for holdDuration while it fills. countdown confirms, then counts down countdown seconds that Cancel or Escape can still stop.
holdDurationnumber1000Milliseconds the confirm button must be held in hold mode.
countdownnumber3Seconds counted down before the action runs in countdown mode.
countdownLabelstring–Text before the seconds in countdown mode, such as "Deleting in". Defaults to pendingLabel followed by "in".
onConfirm() => void | Promise<unknown>–Runs on confirm. Return a promise to show the pending face; a rejection shows the error face with Retry.
onUndo() => void | Promise<unknown>–Adds Undo to the result. Return a promise to show a pending face while it runs.
onCancel() => void–Called when the question is cancelled, including by Escape, outside press, or timeout.
state"idle" | "confirming" | "pending" | "done" | "error"–Controlled state. Pair it with onStateChange.
defaultState"idle" | "confirming" | "pending" | "done" | "error""idle"Starting state when uncontrolled.
onStateChange(state: ConfirmMorphState) => void–Called on every state change.
confirmTimeoutnumber6000Milliseconds before an unanswered question returns to rest. Hovering pauses it; 0 turns it off.
resultTimeoutnumber5000Milliseconds a result stays before returning to rest. Hovering pauses it; 0 turns it off.
cancelOnOutsidePressbooleantrueA press outside the control cancels an open question.
disabledbooleanfalseDisables the resting button.
classNamestring–Class on the root.
refRef<HTMLDivElement>–The root element, which also takes focus while the action is pending.

Keyboard interactions

KeysAction
Enter / SpacePresses the focused face button: start, Confirm, Cancel, Undo, or Retry. In hold mode, holding Enter or Space on Confirm fills it.
EnterWhile asking, confirms from the question (Confirm takes focus when it opens); during a countdown, runs the action now.
Tab / Shift+TabMoves between Cancel and Confirm while asking.
EscapeCancels the question or the countdown, or dismisses a result back to rest.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Also in buttons

Guidance for AI tools

Confirm morph: A destructive button that morphs into an inline confirmation, a spinner, and a result with undo. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://ui.xzero.co.uk/llms.txt

Browse all components