Alert Dialog
A modal dialog that requires explicit user action before proceeding. Cannot be dismissed by clicking the overlay. Built on Radix UI with Framer Motion animations.
Basic
A blocking modal that requires the user to make an explicit choice before continuing. Unlike Dialog, clicking the overlay does not dismiss it — the user must press Cancel or confirm the action.
Installation
Install the component via the CLI in one command.
npx @work-rjkashyap/unified-ui add alert-dialogpnpm dlx @work-rjkashyap/unified-ui add alert-dialognpx @work-rjkashyap/unified-ui add alert-dialogbunx @work-rjkashyap/unified-ui add alert-dialogIf you haven't initialized your project yet, run npx @work-rjkashyap/unified-ui init first. See the CLI docs for details.
Or install the full package
Use this approach if you prefer to install the entire design system as a dependency instead of copying individual components.
npm install @work-rjkashyap/unified-uipnpm add @work-rjkashyap/unified-uiyarn add @work-rjkashyap/unified-uibun add @work-rjkashyap/unified-uiAnatomy
import {
AlertDialog,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
Button,
} from "@work-rjkashyap/unified-ui";Basic Usage
Wrap a trigger in AlertDialogTrigger and provide the content structure. The user must press either AlertDialogAction or AlertDialogCancel — clicking the overlay has no effect.
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="danger">Delete</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action is permanent and cannot be reversed.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction>Continue</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>Destructive Variant
Style the action button as a danger action for destructive operations.
Controlled Mode
Use open and onOpenChange for programmatic control — useful for triggering the dialog from custom logic without a visible trigger element.
const [open, setOpen] = useState(false);
function handleDeleteClick() {
// Any logic before showing confirmation
setOpen(true);
}
async function handleConfirm() {
await deleteItem(item.id);
setOpen(false);
}
<AlertDialog open={open} onOpenChange={setOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete "{item.name}"?</AlertDialogTitle>
<AlertDialogDescription>
This item will be permanently deleted from your workspace.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel onClick={() => setOpen(false)}>
Cancel
</AlertDialogCancel>
<AlertDialogAction onClick={handleConfirm}>
Delete
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>;With Loading State
Combine with a loading flag to disable actions while an async operation completes.
function DeleteDialog({ onDelete }: { onDelete: () => Promise<void> }) {
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false);
const handleConfirm = async () => {
setLoading(true);
try {
await onDelete();
setOpen(false);
} finally {
setLoading(false);
}
};
return (
<AlertDialog open={open} onOpenChange={setOpen}>
<AlertDialogTrigger asChild>
<Button variant="danger">Delete</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Confirm deletion</AlertDialogTitle>
<AlertDialogDescription>
This cannot be undone. Are you sure you want to proceed?
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel disabled={loading}>
Cancel
</AlertDialogCancel>
<AlertDialogAction
onClick={(e) => {
e.preventDefault(); // Prevent auto-close
handleConfirm();
}}
disabled={loading}
className="bg-danger text-danger-foreground hover:bg-danger/90"
>
{loading ? "Deleting..." : "Delete"}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}Non-Destructive Confirmation
Alert dialogs are not only for destructive actions — use them for any critical operation that benefits from explicit confirmation.
AlertDialog vs Dialog
| Feature | AlertDialog | Dialog |
|---|---|---|
| Dismiss on overlay click | ✗ No | ✓ Yes |
| Dismiss on Escape | ✓ Yes | ✓ Yes |
| Requires explicit action | ✓ Always | ✗ Optional |
| Use for destructive actions | ✓ Recommended | ✗ Not recommended |
AlertDialogAction / Cancel | ✓ Built-in | ✗ Custom |
| ARIA role | alertdialog | dialog |
Use AlertDialog when the user must explicitly confirm or cancel — never when they might want to simply dismiss without acting.
Props
AlertDialog
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. |
defaultOpen | boolean | — | Initial open state (uncontrolled). |
onOpenChange | (open: boolean) => void | — | Callback when the open state changes. |
AlertDialogContent
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
AlertDialogTitle
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
AlertDialogDescription
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
AlertDialogAction
Extends the native Radix UI AlertDialogAction — auto-closes the dialog when clicked. Pass onClick={(e) => e.preventDefault()} to prevent auto-close (e.g., for async flows).
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Override button styles (e.g., for danger color). |
disabled | boolean | false | Disables the action button. |
AlertDialogCancel
Auto-closes the dialog when clicked. Styled as a secondary button.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
disabled | boolean | false | Disables the cancel button. |
AlertDialogTrigger
Uses Radix UI's AlertDialogTrigger API. Use asChild to render the trigger as your own element.
AlertDialogHeader / AlertDialogFooter
Layout wrappers with no interactive behavior.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
Motion
- Overlay — Uses the
overlayBackdroppreset (opacity: 0 → 0.5,backdrop-blur 0 → 4px, 200ms). - Content — Uses the
modalContentpreset (scale: 0.95 → 1,opacity: 0 → 1, springstiffness: 300, damping: 28). - All animations respect
prefers-reduced-motionviauseReducedMotion()— falls back to simple opacity transitions.
Keyboard Interaction
| Key | Behavior |
|---|---|
Escape | Closes the dialog (same as pressing Cancel). |
Tab | Cycles focus between Cancel and Action buttons (and any focusable content). |
Enter | Activates the focused button. |
Space | Activates the focused button. |
Accessibility
- Built on @radix-ui/react-alert-dialog for full ARIA compliance.
- The content element has
role="alertdialog"— screen readers announce it as an alert, prompting immediate attention. - Focus trap — Focus is contained within the dialog. The Cancel button receives initial focus by default (to prevent accidental confirmation).
- Focus restoration — Focus returns to the trigger element when the dialog closes.
- Escape to close — Pressing
Escapecloses the dialog (treated as cancellation). - No overlay dismiss — Clicking the backdrop does nothing, enforcing explicit choice.
aria-labelledby— Automatically linked toAlertDialogTitle.aria-describedby— Automatically linked toAlertDialogDescription.aria-modal="true"— Prevents screen readers from interacting with content behind the dialog.
Design Tokens
| Token | Usage |
|---|---|
--background | Dialog panel background |
--border | Dialog panel border |
--overlay | Backdrop overlay color |
--radius-lg | Dialog border radius |
--z-modal | Z-index for dialog content |
--z-overlay | Z-index for backdrop |
--shadow-xl | Dialog panel shadow |
--primary | Default action button color |
--danger | Destructive action button color |