Skip to content

Alert dialog

Asks a question people must answer before going on, like confirming a delete.

Library
What’s this?

Installation

pnpm dlx shadcn@latest add @wisty/alert-dialog

The CLI installs the Radix or Base UI file to match your project, with what it builds on: button.

If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.

When to use

Use it

  • People confirm an action they can't easily undo, like deleting a record or discarding changes.
  • A system problem stops the current task and people must acknowledge it, like a service that's down.
  • A short yes or no question must be answered before going on.

Don't use it

  • People need to fill in fields or do a task. Use Dialog.
  • The message needs no answer, like a saved record. Use Sonner.
  • The problem belongs to one part of the page, like a form section. Use Alert.
  • People should keep the page in view while they work. Use Sheet or Popover.

Usage

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogMedia,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
AlertDialog
├── AlertDialogTrigger
└── AlertDialogContent
    ├── AlertDialogHeader
    │   ├── AlertDialogMedia (optional icon)
    │   ├── AlertDialogTitle
    │   └── AlertDialogDescription
    └── AlertDialogFooter
        ├── AlertDialogCancel
        └── AlertDialogAction

Style the trigger with className={buttonVariants()} from Button, as the examples do.

AlertDialogAction and AlertDialogCancel close the dialog as soon as they're clicked. To keep it open while the action runs, like a delete that waits for the server, control open and put a Button in the footer in place of the Action:

const [open, setOpen] = useState(false)

async function remove() {
  await deleteAccount()
  setOpen(false)
}

return (
  <AlertDialog open={open} onOpenChange={setOpen}>
    {/* trigger and header as in the examples, then in the footer: */}
    {/* <Button variant="destructive" onClick={remove}>Delete</Button> */}
  </AlertDialog>
)

Examples

Header colors

The plain, success and info headers, set with `variant` on `AlertDialogContent`, each with Cancel and a brand action.

Warning

A service that's down, with `variant="warning"` and a single `AlertDialogCancel` as the Okay button.

Small with media

A short question with its buttons side by side, set with `size="sm"`, and an icon in `AlertDialogMedia`.

API reference

PartBuilt on
AlertDialogRadix AlertDialog.Root (opens in a new tab)
AlertDialogTriggerRadix AlertDialog.Trigger (opens in a new tab)
AlertDialogPortalRadix AlertDialog.Portal (opens in a new tab)
AlertDialogOverlayRadix AlertDialog.Overlay (opens in a new tab)
AlertDialogContentRadix AlertDialog.Content (opens in a new tab)
AlertDialogHeader<div> (opens in a new tab)
AlertDialogFooter<div> (opens in a new tab)
AlertDialogMedia<div> (opens in a new tab)
AlertDialogTitleRadix AlertDialog.Title (opens in a new tab)
AlertDialogDescriptionRadix AlertDialog.Description (opens in a new tab)
AlertDialogActionRadix AlertDialog.Action (opens in a new tab)
AlertDialogCancelRadix AlertDialog.Cancel (opens in a new tab)

AlertDialogContent

PropTypeDefault
size"default" | "sm""default"
variant"default" | "destructive" | "warning" | "success" | "info""default"

AlertDialogAction

PropTypeDefault
variant"default" | "outline" | "secondary" | "ghost" | "destructive" | "link" | "outline-brand" | "destructive-text" | "success" | "inverse""default"
size"default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg""default"

AlertDialogCancel

PropTypeDefault
variant"default" | "outline" | "secondary" | "ghost" | "destructive" | "link" | "outline-brand" | "destructive-text" | "success" | "inverse""outline"
size"default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg""default"

SLDS mapping

AlertDialogContent is slds-modal slds-modal_prompt, and AlertDialogOverlay is slds-backdrop, as Dialog's. AlertDialogHeader is slds-modal__header, themed by variant, and AlertDialogTitle is its slds-text-heading_medium heading. AlertDialogDescription is the prompt's message in slds-modal__content, on the box's own background under the themed header. A link in it takes the link color, underlined so it doesn't rely on color alone. AlertDialogFooter is slds-modal__footer slds-theme_default. AlertDialogMedia has no SLDS counterpart: it's Empty's gray icon box. The title's alignment, the footer's rule and its button alignment follow each theme's prompt hooks.

Known gaps:

  • SLDS's striped header texture (slds-theme_alert-texture) isn't in the SLDS 2 stylesheet, so it isn't here either.
  • Icons are lucide's, not SLDS's utility icons.
PropValueSLDSNotes
sizedefaultslds-modal slds-modal_prompt40rem at most, as dialog.
sizesmslds-modal slds-modal_prompt20rem, SLDS's smallest modal width, with the footer buttons side by side. SLDS has no small prompt.
variantdefault (added)slds-modal__headerThe header on the box's background.
variantdestructive (added)slds-modal__header slds-theme_error
variantwarning (added)slds-modal__header slds-theme_warning
variantsuccess (added)slds-modal__header slds-theme_success
variantinfo (added)slds-modal__header slds-theme_info

Keyboard interactions

Keys Action
Escape Closes the dialog and returns focus to the trigger. With a combobox's list open inside, closes only the list; press again.
Tab, Shift+Tab Moves between the dialog's controls and stays inside it.

A Command's search field isn't an open list, so Escape there closes the dialog.

Accessibility

  • Always include an AlertDialogTitle and an AlertDialogDescription. They name and describe the dialog, so screen readers read the question when it opens.
  • Always include an AlertDialogCancel, first in the footer, even when it's the only button, like an Okay. Focus moves to it on open; without one, focus can stay on the trigger behind the dialog.
  • Clicking outside doesn't close the dialog. People choose a button or press Escape.

Motion

  • The backdrop and the box fade in, the box faster, as Dialog's do, in every theme. Nothing moves, so the fades stay on with reduced motion.

Responsive behavior

  • From 48rem (768px) wide, the dialog is half the screen wide, between 20rem and 40rem. Below it, it fills the screen less 2rem on each side. size="sm" stays at 20rem or less.
  • The title wraps and long words break. Footer buttons wrap onto a second line when they don't fit; in size="sm" they share the row in two equal columns.

Performance

  • The content renders in a portal at document.body, only while open, so styles scoped to an ancestor don't reach it.

Rules

  • For a delete or another destructive action, pass variant="destructive" to both AlertDialogContent and AlertDialogAction.
  • Use variant="warning" for a system problem people must acknowledge, with a single Cancel such as "Okay", as the Warning example shows.
  • Don't restyle the header, corners or colors with utility classes. They come from the theme tokens.