Components / Actions
ConfirmMorph
A destructive button that morphs into an inline confirmation, a spinner, and a result with undo.
Install
npx shadcn@latest add https://irisui.dev/r/confirm-morph.jsonimport { ConfirmMorph } from "@/components/iris/confirm-morph/confirm-morph";Preview
ConfirmMorph
A destructive or important button that asks in place: it morphs into an inline question with Cancel and Confirm, then a spinner, then a result with Undo.
When to use
- Deleting a project, revoking access, discarding a draft — where a modal dialog would be heavy but a single tap is too easy.
- When the action can be undone for a moment (pass
onUndo), or should run after a short cancellable countdown (confirmMode="countdown"). - When people must read consequences before confirming, use a dialog. For a hold gesture with no question, use
HoldToConfirm.
Usage
import { ConfirmMorph } from "@/components/iris/confirm-morph/confirm-morph";
<ConfirmMorph
label="Delete project"
icon={<TrashIcon size={16} />}
prompt="Delete project blog?"
onConfirm={() => api.deleteProject(id)}
onUndo={() => api.restoreProject(id)}
/>;
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label |
ReactNode |
— | Resting label (required). |
icon |
ReactNode |
— | Icon before the resting label. |
prompt |
ReactNode |
label + "?" | The question while confirming. |
confirmLabel / cancelLabel |
string |
"Delete" / "Cancel" |
Buttons in the question. |
pendingLabel / doneLabel / errorLabel / retryLabel |
string |
"Deleting" / "Deleted" / "Couldn’t finish" / "Retry" |
Labels for the later faces. |
undoLabel / undoingLabel |
string |
"Undo" / "Restoring" |
Undo button and its pending text. |
tone |
"danger" | "neutral" |
"danger" |
Confirm button colour: danger, or the accent for reversible actions. |
confirmMode |
"press" | "hold" | "countdown" |
"press" |
How the question is answered. |
holdDuration |
number |
1000 |
Ms to hold in hold mode. |
countdown / countdownLabel |
number / string |
3 / pending label + "in" |
Seconds and text in countdown mode. |
onConfirm |
() => void | Promise<unknown> |
— | Runs on confirm. A promise shows the pending face; a rejection shows the error face with Retry. |
onUndo |
() => void | Promise<unknown> |
— | Adds Undo to the result. |
onCancel |
() => void |
— | Called when the question is cancelled. |
state / defaultState / onStateChange |
"idle" | "confirming" | "pending" | "done" | "error" |
"idle" |
Controlled or uncontrolled state. |
confirmTimeout / resultTimeout |
number |
6000 / 5000 |
Ms before an unanswered question or a result returns to rest; hovering pauses it; 0 turns it off. |
cancelOnOutsidePress |
boolean |
true |
A press outside cancels an open question. |
disabled, className, ref |
— | — | ref receives the root element. |
Notes
- Escape, an outside press or the timeout return it to rest. Focus follows the control between faces only if it was already inside, and the root takes focus while pending.
- The question is labelled for assistive tech, and a polite live region (
<output>) announces pending, done and error faces. - Width springs between faces while faces crossfade at their natural width, so text never squashes. Reduced motion uses instant fades.