ConfirmDialog

An AlertDialog as a single component, with async confirm handling.

Usage

import { ConfirmDialog } from "@voila.dev/ui/confirm-dialog";
<ConfirmDialog
	trigger={<Button variant="outline">Archive project</Button>}
	title="Archive this project?"
	description="The project will be hidden from the active list."
	confirmLabel="Archive"
	onConfirm={() => archiveProject(id)}
/>

The destructive confirmation, assembled. It is AlertDialog with the title, description, two buttons and open state already wired, because every product writes this dialog a dozen times and gets the button labels wrong in half of them. Pass a trigger and it drives itself; omit the trigger and drive it with open and onOpenChange from a menu item or a row action.

Recipes

confirmLabel should name the action and confirmVariant should be destructive when it cannot be undone. The description is where "this cannot be undone" belongs — the title is for the question.

onOpenChange is narrower than Base UI's: the dialog also closes itself around onConfirm, where there is no originating event, so it takes just the boolean.

API

PropTypeDefault
titleReactNoderequiredThe question, as a heading. Name the consequence, not the control.
cancelLabelReactNode"Cancel"Text of the dismiss button.
confirmLabelReactNode"Confirm"Text of the confirm button. Name the action — "Delete project", not "OK".
descriptionReactNodeWhat will happen, in a sentence. The place to say what cannot be undone.
mediaReactNodeIcon slot rendered in AlertDialog.Media beside the title.
onCancel(() => void)Called when the cancel button is clicked (not on Escape/backdrop).
onConfirm(() => Promise<unknown> | undefined)Confirm handler. When it returns a promise the dialog enters a pending state (spinner on the confirm button, cancel disabled, dismissal blocked) and closes once it resolves. On rejection the dialog stays open so the user can retry - surface the failure inside onConfirm (e.g. a toast), the dialog does not report it.
onOpenChange((open: boolean) => void)Called when the dialog opens or closes. Narrower than Base UI's (open, eventDetails), because the dialog also closes itself around onConfirm, where there is no originating event.
size"default" | "sm"Width of the panel. sm suits a one-line confirmation.
triggerReactElement<Record<string, unknown>, string | JSXElementConstructor<any>>Element rendered as the dialog trigger, carrying its own label, e.g. <Button variant="destructive">Delete</Button>. Omit it to drive the dialog through open/onOpenChange instead.
variant"brand" | "default" | "destructive" | "ghost" | "highlight" | "link" | "outline" | "primary" | "secondary""default"Confirm button variant - use destructive for irreversible actions.
actionsRefRefObject<DialogRootActions | null>A ref to imperative actions.
defaultOpenbooleanWhether the dialog is initially open. To render a controlled dialog, use the open prop instead.
defaultTriggerIdstring | nullID of the trigger that the dialog is associated with. This is useful in conjunction with the defaultOpen prop to create an initially open dialog.
handleAlertDialogHandle<unknown>A handle to associate the alert dialog with a trigger. If specified, allows external triggers to control the alert dialog's open state. Can be created with the AlertDialog.createHandle() method.
onOpenChangeComplete((open: boolean) => void)Event handler called after any animations complete when the dialog is opened or closed.
openbooleanWhether the dialog is currently open.
triggerIdstring | nullID of the trigger that the dialog is associated with. This is useful in conjunction with the open prop to create a controlled dialog. There's no need to specify this prop when the dialog is uncontrolled (that is, when the open prop is not set).

Plus the DOM props of the element it renders. Source: confirm-dialog/components/confirm-dialog.tsx.

AlertDialog · Dialog · Button