Skip to content

Alert Dialog

Stable

A modal confirmation that interrupts people before a consequential or irreversible action, and can only be dismissed by making a choice.

Installation

$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/alert-dialog.json

Usage

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogMedia,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
const [open, setOpen] = React.useState(false)

<AlertDialog open={open} onOpenChange={setOpen}>
  <AlertDialogTrigger render={<Button variant="outline" />}>Delete project</AlertDialogTrigger>
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Delete “Atlas”?</AlertDialogTitle>
      <AlertDialogDescription>This can’t be undone.</AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel>Keep project</AlertDialogCancel>
      <AlertDialogAction variant="destructive" onClick={deleteProject}>
        Delete project
      </AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>
The action doesn’t close the dialog
AlertDialogCancel closes the dialog. AlertDialogAction is a plain Button, on purpose: the confirmed work is often asynchronous, and the dialog should stay open — with the action in its loading state — until it succeeds or fails. Control open and close it yourself when the work is done.

Examples

Basic

A title and a description are often enough. The description says what will be lost; the buttons say what each choice does.

Media

AlertDialogMedia adds an icon that sets the tone before the title is read. Match its variant to the consequence — destructive for data loss, warning for disruption, success to confirm something good that can't be taken back, brand for significant but safe actions, default for everything else — and use the same emphasis on the action button.

Small

size="sm" centers the content and splits the footer into two equal buttons. Use it for short, binary questions — permissions and quick opt-ins — especially on mobile.

Typed confirmation

For actions that destroy a lot of work at once, ask people to type the name of what they are deleting. The action stays disabled until the text matches, which prevents confirming out of habit.

Async action

Keep the dialog open while the request runs: put the action in its loading state, disable cancel, and ignore dismissal until the work settles. Then close the dialog and confirm the result with a Toast.

<AlertDialog open={open} onOpenChange={(next) => !pending && setOpen(next)}>
  {/* … */}
  <AlertDialogCancel disabled={pending}>Cancel</AlertDialogCancel>
  <AlertDialogAction variant="destructive" loading={pending} onClick={revoke}>
    Revoke key
  </AlertDialogAction>
</AlertDialog>

Guidelines

When to use

  • Before destructive actions that can't be undone: deleting, revoking, permanently removing people.
  • Before actions with a large blast radius: deploying to production, disconnecting an integration, signing out everywhere.
  • When leaving would lose work that can't be recovered.

When not to use

  • For actions that can be undone — act immediately and offer Undo in a Toast. An undo is always kinder than a confirmation.
  • To collect input or show information — use a Dialog.
  • To tell people something went wrong — use an inline Alert or a toast.

Confirm rarely

Every confirmation trains people to click through the next one. Reserve alert dialogs for the few moments that deserve them, and make those moments specific: name the thing, the number, and the consequence.

Write the choices

The title asks one question. The action repeats the verb from the title, and the cancel button says what staying means. Never use Yes, No or OK.

Delete 3 files?They’ll be gone for everyone.
Do.The question and the buttons use the same verb.
Are you sure?This action is permanent.
Don’t.“Yes” and “No” make people reread the question under pressure.

Order and emphasis

Put the action last — on the right from sm up, on top when the footer stacks on mobile — and cancel before it. Use the destructive button only for destructive actions; the red means you are about to lose something.

Accessibility

The alert dialog follows the WAI-ARIA alert dialog pattern. Base UI renders it with role="alertdialog", labels it with the title and describes it with the description, so screen readers announce the consequence as soon as it opens.

KeyBehavior
EnterSpace
On the trigger: opens the alert dialog.
Tab
Moves between the choices. Focus is trapped inside the dialog.
ShiftTab
Moves focus backwards, wrapping at the start.
Esc
Closes the dialog, the same as choosing Cancel, and returns focus to the trigger.
  • No outside dismissal. Clicking the scrim doesn't close an alert dialog: people must choose. Esc still works as Cancel.
  • Title and description are required. They are the only way a screen reader user learns what they are confirming.
  • Focus. Focus moves to the first focusable element — usually the cancel button, the safe choice — and returns to the trigger afterwards.
  • Color is never the only signal. The destructive action is red, and its label also says Delete.

API reference

AlertDialog

The root. Doesn't render an element. Accepts every prop of Base UI AlertDialog.Root — the same as Dialog, minus modal and disablePointerDismissal, which are always on.

PropTypeDefault
open

Whether the alert dialog is open. Control it when the action is asynchronous.

booleanNo default
defaultOpen

Whether it is open initially, when uncontrolled.

booleanfalse
onOpenChange

Called when it opens or closes.

(open: boolean, details) => voidNo default
onOpenChangeComplete

Called after the enter or exit animation finishes.

(open: boolean) => voidNo default
actionsRef

Imperative handle to close or unmount the dialog.

RefObject<{ close, unmount }>No default

AlertDialogContent

Renders the portal, scrim and popup.

PropTypeDefault
size

sm centers the content, narrows the dialog and splits the footer into two equal buttons.

"default" | "sm""default"
initialFocus

Element to focus when it opens.

boolean | RefObject | (interaction) => HTMLElement | booleanNo default
finalFocus

Element to focus when it closes.

boolean | RefObject | (interaction) => HTMLElement | booleanNo default

AlertDialogMedia

An icon badge shown beside the title (or above it on small dialogs).

PropTypeDefault
variant

Color of the badge. Match it to the consequence of the action.

"default" | "destructive" | "warning" | "success" | "brand""default"

AlertDialogAction

A prfct Button. Accepts every Button prop — variant, loading, disabled — and does not close the dialog.

AlertDialogCancel

Closes the dialog. Renders a prfct Button.

PropTypeDefault
variant

Visual emphasis of the button.

Button variant"outline"
size

Size of the button.

Button size"default"

AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter

Layout parts. AlertDialogTitle renders an <h2> and names the dialog; AlertDialogDescription renders a <p> and describes it. AlertDialogFooter stacks the choices on small screens and right-aligns them from sm up.