← All components
overlays / stable

AlertDialog

Confirmation dialog (role alertdialog) with a required title and description; `danger` for irreversible actions.

LIVE PREVIEW
Loading preview…

When to use

  • Before an irreversible or costly action: delete, send to client, revoke access.
  • When the user must explicitly choose before continuing.

Consider an alternative

  • Undoable actions — do it, then offer Undo in a toast.
  • Forms or multi-step tasks — use Dialog.

Import

import { AlertDialog } from '@revido-llc/kit';

Keyboard interaction

  • Escape — cancel
  • Tab — move between Cancel and Confirm (Cancel is focused first)
  • Hold to confirm: hold Space or Enter on the confirm button for the full duration; release early to cancel

Props

Props documented by the Kit. Refer to the TypeScript types for the complete interface, including inherited props.

description (required)ReactNode—What happens and whether it can be undone. Required.
title (required)ReactNode—The question or statement, e.g. "Delete this project?". Required.
cancelLabelReactNode"Cancel"Cancel button label. Default "Cancel".
childrenReactNode—Optional extra content (e.g. a list of affected items).
classNamestring—
closeOnConfirmbooleantrueClose after onConfirm resolves. Set false when the app closes only after a successful save.
confirmLabelReactNode—Confirm button label. Default "Confirm" ("Delete" when `danger`).
confirmMode"click" | "hold""click"How the confirm button is activated. `click` (default) is a normal press; `hold` requires pressing and holding it for `holdDurationMs` while a fill shows progress (or holding Space/Enter) — for irreversible actions like Delete. Releasing early cancels. Screen-reader activation (no hold possible) confirms immediately.
dangerbooleanfalseIrreversible action: the confirm button uses the `danger` variant.
defaultOpenboolean—
holdDurationMsnumber1200Hold time in milliseconds for `confirmMode="hold"`.
isConfirmDisabledbooleanfalseBlock confirmation for validation/stale previews while Cancel and body controls remain usable.
isOpenboolean—Controlled open state (only when not inside a `DialogTrigger`).
isPendingbooleanfalseApp-owned pending work. Disables Cancel/Confirm and Escape while a save runs.
onCancel(() => void)—Runs when the user cancels: the Cancel button, or Escape when controlled with `isOpen`. Inside a `DialogTrigger`, Escape is reported by the trigger's `onOpenChange`.
onConfirm(() => void | Promise<unknown>)—Runs on confirm. Return a promise to keep the dialog open with a loading button until it settles; it closes on success and stays open on rejection (show the error yourself — the rejection is not swallowed).
onOpenChange((isOpen: boolean) => void)—

Examples

Destructive

Danger confirm, Cancel focused, never closes on backdrop click.

<DialogTrigger>
  <Button variant="danger">Delete project</Button>
  <AlertDialog
    danger
    title="Delete Website redesign?"
    description="Its 48 tasks are removed for everyone. This can't be undone."
    confirmLabel="Delete project"
    onConfirm={deleteProject}
  />
</DialogTrigger>

Hold to confirm

confirmMode="hold": press and hold the confirm button (mouse, touch, or Space/Enter) until the fill completes. Releasing early cancels. For irreversible actions where a stray click must not be enough.

<AlertDialog
  danger
  confirmMode="hold"
  holdDurationMs={1200} // default
  title="Delete Website redesign?"
  description="Its 48 tasks are removed for everyone. This can't be undone."
  confirmLabel="Delete project"
  onConfirm={deleteProject}
/>

Async confirm

Return a promise from onConfirm: the button shows a spinner and the dialog closes when it resolves.

<AlertDialog
  title="Send proposal to Acme?"
  description="The client gets an email with a link to review and sign."
  confirmLabel="Send"
  onConfirm={() => sendProposal(id)}
/>

Literal anatomy

Static component anatomy; bind events in the consuming app.

<AlertDialog title="Delete draft?" description="This draft will be removed." danger />

App-owned persistence

Both actions and Escape are disabled while saving. A handled failure stays open; the app closes only after persistence succeeds.

<AlertDialog isOpen={open} onOpenChange={setOpen} isPending={pending} closeOnConfirm={false}
  title="Delete file?" description="The file will be removed." onConfirm={async () => {
    setPending(true);
    try { await deleteFile(); setOpen(false); } catch (error) { showError(error); }
    finally { setPending(false); }
  }} />

Related components