Confirm Dialog

A decision that has to be made before anything else happens. Outside clicks never dismiss it.

Basic

<ConfirmDialog
open={open}
onOpenChange={setOpen}
title="Publish changes?"
message="The updated rates go live immediately."
confirmLabel="Publish"
onConfirm={publish}
/>

Destructive

Pass tone="danger" for destructive confirms. It is not inferred from the label — a guess that reads English words can't be right in every locale, and getting it wrong paints a harmless action red or a destructive one ember.

Async confirm

closeOnConfirm={false} keeps the sheet open so you can close it yourself once the work finishes. While isLoading is true, Escape and both buttons are blocked, so a request can't be fired twice or abandoned halfway.

<ConfirmDialog
open={open}
onOpenChange={setOpen}
isLoading={saving}
closeOnConfirm={false}
onConfirm={async () => {
setSaving(true);
await retry();
setSaving(false);
setOpen(false);
}}
/>

Why not react-alert-dialog

This is @radix-ui/react-dialog with role="alertdialog", not @radix-ui/react-alert-dialog. That package bundles its own nested copy of react-dialog, so its focus and dismiss layer stack is a different module instance from the one Modal uses. Open this over a Modal and clicks stop reaching the top sheet; on close it can restore pointer-events: none on the body and freeze the page.

If you need to close an underlying dialog once this one goes away, use onClosed rather than doing it in onConfirm — closing two modals in the same tick corrupts Radix's overlay accounting in the same way.