Use a modal prompt when an action deserves one last check. It includes a portal overlay, Escape dismissal, and controlled or uncontrolled open state.
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger,} from "@/components/ui/alert-dialog"export function Example() { return ( <AlertDialog> <AlertDialogTrigger>Ship update</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Ship this docs update?</AlertDialogTitle> <AlertDialogDescription> The changelog entry and component pages go live for everyone on the current namespace. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Not yet</AlertDialogCancel> <AlertDialogAction>Ship</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> )}Installation
npx @arctis-sh/@arctis-sh/ui@latest add alert-dialogUsage
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger,} from "@/components/ui/alert-dialog"<AlertDialog> <AlertDialogTrigger>Publish draft</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Publish this draft?</AlertDialogTitle> <AlertDialogDescription> This page will be visible to everyone in the current namespace. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Keep editing</AlertDialogCancel> <AlertDialogAction>Publish</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent></AlertDialog>Composition
AlertDialog
├── AlertDialogTrigger
└── AlertDialogContent
├── AlertDialogHeader
│ ├── AlertDialogMedia
│ ├── AlertDialogTitle
│ └── AlertDialogDescription
└── AlertDialogFooter
├── AlertDialogCancel
└── AlertDialogActionAlertDialogMedia is optional. When it contains an icon, the title and description sit beside it.
Basic
The trigger opens the dialog. Cancel closes it, while the action confirms the choice.
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger,} from "@/components/ui/alert-dialog"export function Example() { return ( <AlertDialog> <AlertDialogTrigger>Ship update</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Ship this docs update?</AlertDialogTitle> <AlertDialogDescription> The changelog entry and component pages go live for everyone on the current namespace. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Not yet</AlertDialogCancel> <AlertDialogAction>Ship</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> )}Small
Set size="sm" on AlertDialogContent for a more compact panel.
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger,} from "@/components/ui/alert-dialog"export function Example() { return ( <AlertDialog> <AlertDialogTrigger>Discard edits</AlertDialogTrigger> <AlertDialogContent size="sm"> <AlertDialogHeader> <AlertDialogTitle>Discard local edits?</AlertDialogTitle> <AlertDialogDescription> Unsaved markdown changes in this tab will be dropped. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Keep</AlertDialogCancel> <AlertDialogAction>Discard</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> )}Outline
Set variant="outline" on AlertDialogContent for a bordered panel.
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger,} from "@/components/ui/alert-dialog"export function Example() { return ( <AlertDialog> <AlertDialogTrigger>Ship update</AlertDialogTrigger> <AlertDialogContent variant="outline"> <AlertDialogHeader> <AlertDialogTitle>Ship this docs update?</AlertDialogTitle> <AlertDialogDescription> The changelog entry and component pages go live for everyone on the current namespace. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Not yet</AlertDialogCancel> <AlertDialogAction>Ship</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> )}With icon
Use AlertDialogMedia for a leading icon with the copy beside it.
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogTitle, AlertDialogTrigger,} from "@/components/ui/alert-dialog"export function Example() { return ( <AlertDialog> <AlertDialogTrigger>Pull component</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogMedia> <PackageIcon /> </AlertDialogMedia> <AlertDialogTitle>Add alert to this repo?</AlertDialogTitle> <AlertDialogDescription> Files write into src/components/ui. You own them after install — no package lock-in. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogAction>Add</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> )}Small with icon
Combine size="sm" with AlertDialogMedia.
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogTitle, AlertDialogTrigger,} from "@/components/ui/alert-dialog"export function Example() { return ( <AlertDialog> <AlertDialogTrigger>Revert theme</AlertDialogTrigger> <AlertDialogContent size="sm"> <AlertDialogHeader> <AlertDialogMedia> <WarningIcon /> </AlertDialogMedia> <AlertDialogTitle>Revert theme tokens?</AlertDialogTitle> <AlertDialogDescription> Custom CSS variables snap back to the starter defaults. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogAction>Revert</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> )}With image
AlertDialogMedia can span the full width to place a preview image above the copy.
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogTitle, AlertDialogTrigger,} from "@/components/ui/alert-dialog"export function Example() { return ( <AlertDialog> <AlertDialogTrigger>Open preview</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogMedia className="col-span-full mb-3 h-44 w-full overflow-hidden rounded-sm p-0 sm:h-52"> <img src="/assets/brand/demos/alert-dialog-preview.png" alt="" /> </AlertDialogMedia> <AlertDialogTitle className="!col-start-1"> Open staged preview? </AlertDialogTitle> <AlertDialogDescription className="!col-start-1"> Share a temporary build of the docs. The link expires after seven days. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Close</AlertDialogCancel> <AlertDialogAction>Open</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> )}Delete confirm
A destructive confirmation with a clear icon and action.
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogTitle, AlertDialogTrigger,} from "@/components/ui/alert-dialog"export function Example() { return ( <AlertDialog> <AlertDialogTrigger variant="destructive"> Delete demo </AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogMedia className="bg-destructive/10 text-destructive"> <TrashIcon /> </AlertDialogMedia> <AlertDialogTitle>Delete this demo scene?</AlertDialogTitle> <AlertDialogDescription> The preview and its code sample leave the docs page. You can add the scene again later from the registry. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogAction variant="destructive">Delete</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> )}Type to confirm
Require the user to enter matching text before enabling a destructive action.
import { useState } from "react"import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger,} from "@/components/ui/alert-dialog"const CONFIRM_TEXT = "drop-namespace"export function Example() { const [value, setValue] = useState("") return ( <AlertDialog onOpenChange={(open) => { if (!open) setValue("") }} > <AlertDialogTrigger variant="destructive"> Drop namespace </AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Drop @arctis permanently?</AlertDialogTitle> <AlertDialogDescription> Installs that point at this namespace will fail. Type{" "} <span className="font-medium text-foreground">{CONFIRM_TEXT}</span>{" "} to continue. </AlertDialogDescription> </AlertDialogHeader> <input value={value} onChange={(event) => setValue(event.target.value)} placeholder={CONFIRM_TEXT} className="mt-4 w-full rounded-sm border border-input bg-background px-3 py-2 text-sm outline-none" /> <AlertDialogFooter> <AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogAction variant="destructive" disabled={value !== CONFIRM_TEXT} > Drop </AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> )}API Reference
AlertDialog
| Prop | Type | Default |
|---|---|---|
| open | boolean | — |
| defaultOpen | boolean | false |
| onOpenChange | (open: boolean) => void | — |
<AlertDialog> <AlertDialogTrigger variant="outline">Open</AlertDialogTrigger> <AlertDialogContent> <AlertDialogTitle>Are you sure?</AlertDialogTitle> <AlertDialogDescription>This cannot be undone.</AlertDialogDescription> <AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogAction>Continue</AlertDialogAction> </AlertDialogContent></AlertDialog>AlertDialogTrigger
Renders a Button and accepts the same props, including variant, size, and loading.
| Prop | Type | Default |
|---|---|---|
| variant | Button variant | "default" |
| size | Button size | "sm" |
| className | string | — |
<AlertDialogTrigger variant="outline">Open</AlertDialogTrigger>AlertDialogContent
| Prop | Type | Default |
|---|---|---|
| size | "default" | "sm" | "default" |
| variant | "default" | "outline" | "default" |
| className | string | — |
<AlertDialogContent> <AlertDialogTitle>Are you sure?</AlertDialogTitle> <AlertDialogDescription>This cannot be undone.</AlertDialogDescription></AlertDialogContent>AlertDialogMedia
| Prop | Type | Default |
|---|---|---|
| className | string | — |
<AlertDialogMedia> <Icon /></AlertDialogMedia>AlertDialogTitle
| Prop | Type | Default |
|---|---|---|
| className | string | — |
<AlertDialogTitle>Are you sure?</AlertDialogTitle>AlertDialogDescription
| Prop | Type | Default |
|---|---|---|
| className | string | — |
<AlertDialogDescription> This cannot be undone.</AlertDialogDescription>AlertDialogCancel
| Prop | Type | Default |
|---|---|---|
| className | string | — |
<AlertDialogCancel>Cancel</AlertDialogCancel>AlertDialogAction
| Prop | Type | Default |
|---|---|---|
| variant | "default" | "destructive" | "default" |
| className | string | — |
| disabled | boolean | false |
<AlertDialogAction>Continue</AlertDialogAction>