Home

Alert dialog and confirm

A dialog that asks one question before something happens; `ConfirmDialog` is its ready form for a destructive action, where the thing's name must be typed first.

ui.alert-dialogcomponents/ui/confirm-dialog.tsx

Use case

For the AI

Reach for it when an action cannot be undone or throws work away: deleting an invoice, removing a client and everything filed under it, leaving a page with unsaved changes. For anything destructive use `ConfirmDialog`: it says what is lost, asks for the record's own name to be typed exactly, and wakes the red button only on a match. A question that destroys nothing (leave the page, keep a draft) is a plain `AlertDialog` with no typing.

Use it when

  • Deleting a record that other records depend on
  • An action with no undo, such as voiding an invoice
  • Leaving a page that holds unsaved work
  • A choice the person must answer before anything else happens

Use something else when

  • Entering or editing values rather than answering a question: Dialog
  • A reversible action: do it at once and offer Undo: Toast
  • A warning that stays on the page while the person keeps working: Alert

Examples

Destructive: the name typed exactly before the red button wakes
A question that destroys nothing: no typing

Code

Import

import { Button } from "@/components/ui/button"
import { ConfirmDialog } from "@/components/ui/confirm-dialog"
import {
  AlertDialog,
  AlertDialogClose,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogPopup,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"

Usage

<>
  <ConfirmDialog
    trigger={<Button variant="destructive-outline" />}
    triggerLabel="Delete the Invoice"
    title="Delete INV-2026-014?"
    description="Its lines, payments and history go with it. This cannot be undone."
    confirmText="INV-2026-014"
    actionLabel="Delete the Invoice"
    onConfirm={() => deleteInvoice(invoice.id)}
  />
  <AlertDialog>
    <AlertDialogTrigger render={<Button variant="secondary" />}>Leave the Page</AlertDialogTrigger>
    <AlertDialogPopup className="sm:max-w-sm">
      <AlertDialogHeader>
        <AlertDialogTitle>Leave without saving?</AlertDialogTitle>
        <AlertDialogDescription>Your changes to the invoice are kept as a draft.</AlertDialogDescription>
      </AlertDialogHeader>
      <AlertDialogFooter>
        <AlertDialogClose render={<Button variant="ghost" />}>Stay</AlertDialogClose>
        <AlertDialogClose render={<Button />}>Leave</AlertDialogClose>
      </AlertDialogFooter>
    </AlertDialogPopup>
  </AlertDialog>
</>

Rules

  • A destructive action goes through `ConfirmDialog`: the description names what is lost, and the red button wakes only once `confirmText` is typed exactly.
  • The title is the question about the thing by its name ("Delete Inventory Dashboard?"), and the action button repeats the verb ("Delete the Project"), never a bare OK.
  • An alert dialog has no close button and ignores a click outside, so its footer always holds the way back, first: Cancel or Stay.
  • `onConfirm` may return a promise: the button shows its loading state and the dialog closes only when it resolves, staying open if it throws.
  • On a French page pass `typeLead`, `typeTail` and `cancelLabel` so every word around the name is French.