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-dialog
components/ui/confirm-dialog.tsxUse case
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.