Components
AlertDialog
A modal that asks the user to confirm a destructive action. Same look as Dialog but narrower, with no corner close. Focus starts on Cancel, and a scrim click does not close it.
Preview
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive-soft">Delete project</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete project?</AlertDialogTitle>
<AlertDialogDescription>This removes the project and all its files for everyone on your team. You can't undo it.</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction>Delete project</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>Usage
When to use
- Confirm an action that destroys data or can't be undone, such as deleting a project.
- Guard a destructive action against a stray key press or click: focus starts on Cancel, and a scrim click doesn't close the dialog.
When not to use
- Forms, non-destructive choices, or confirming an action that destroys no data and can be undone. Use Dialog.
- A status that asks for no decision, such as a failed build. Use Badge.
Examples
Delete project
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive-soft">Delete project</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete project?</AlertDialogTitle>
<AlertDialogDescription>This removes the project and all its files for everyone on your team. You can't undo it.</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction>Delete project</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>Do and don't
Do
- Use it only to confirm an action that destroys data or can't be undone.
- Write the title as the question and the action button as the verb plus the object ("Delete project").
- Say in the description what is lost and for whom.
- Keep Cancel first in the footer markup; the footer puts it left on desktop and at the bottom on mobile.
Don't
- Don't label the action "Continue", "OK" or "Yes".
- Don't add a corner close or close on a scrim click.
- Don't move initial focus to the action button.
- Don't use it for forms or non-destructive choices; use Dialog.
- Don't leave out AlertDialogDescription.
Props
| Name | Type | Values | Default | Description |
|---|---|---|---|---|
| open | boolean | - | - | Set on AlertDialog. Whether the dialog is open, when you control it. Pair it with onOpenChange. Only on web. |
| defaultOpen | boolean | - | false | Set on AlertDialog. Opens the dialog on first render, when you don't control it. Only on web. |
| onOpenChange | function | - | - | Set on AlertDialog. Called with true or false when the dialog opens or closes (trigger, Cancel, Action, Escape). Close it yourself after an async action by controlling open. Only on web. |
Slots
| Name | Required | Description |
|---|---|---|
| trigger | no | Element that opens the dialog. |
| title | yes | The question, required for a11y. |
| description | yes | What happens if the user confirms. Required. |
| cancel | yes | AlertDialogCancel: closes only. Secondary button by default. |
| action | yes | AlertDialogAction: closes and runs the destructive action. Destructive button by default, labeled with the action. |
Anatomy
| Part | Description |
|---|---|
| root | Root. Controls open state. |
| overlay | Scrim behind the content. color-overlay-scrim. Clicking it does nothing. |
| content | The floating panel: Dialog's panel, at most max-w-md wide. |
| header | Title and description, left-aligned. No icon in v1. |
| title | Accessible name. States the question ("Delete project?"). |
| description | Required. Says what will happen and that it can't be undone. |
| footer | Cancel (secondary) then the action (destructive). Cancel sits left on desktop and at the bottom on mobile. |
Accessibility
Role: alertdialog
| Keys | Action |
|---|---|
| Escape | Cancels: closes the dialog and returns focus to the trigger. |
| Tab | Cycles focus inside the dialog (focus trap). |
| Enter / Space | Activates the focused button. Cancel has focus when the dialog opens. |
- role="alertdialog", named by AlertDialogTitle (aria-labelledby) and described by AlertDialogDescription (aria-describedby). Both are required.
- Traps focus and hides the rest of the page from assistive tech (aria-hidden on siblings), same as Dialog.
- Focus moves to AlertDialogCancel on open, so a stray Enter doesn't destroy anything.
- No corner close and no close on a scrim click. Cancel and Escape are the only ways out besides the action.
- Focus returns to the trigger on close.
Install
npx shadcn add https://werewolf-ui.vercel.app/r/alert-dialog.jsonThis also adds styles/werewolf.css, the tokens every component uses, and any other component it needs. Import that file once in your root CSS, after @import "tailwindcss", with a path relative to that CSS file (from app/globals.css it is @import "../styles/werewolf.css").