Installation
CLI
npx shadcn@latest add "https://eo-n.vercel.app/r/alert-dialog"
Manual
Copy and paste the following code into your project.
"use client";
import * as React from "react";
import { AlertDialog as AlertDialogPrimitive } from "@base-ui-components/react/alert-dialog";
import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/ui/button";
function AlertDialog({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
}
function AlertDialogTrigger({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
return (
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
);
}
function AlertDialogPortal({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
return (
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
);
}
function AlertDialogBackdrop({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Backdrop>) {
return (
<AlertDialogPrimitive.Backdrop
data-slot="alert-dialog-backdrop"
className={cn(
"fixed inset-0 z-50 bg-black/50 backdrop-blur-[1.5px] transition-colors duration-150 ease-out data-[ending-style]:opacity-0 data-[starting-style]:opacity-0",
className
)}
{...props}
/>
);
}
function AlertDialogContent({
className,
children,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Popup>) {
return (
<AlertDialogPortal>
<AlertDialogBackdrop />
<AlertDialogPrimitive.Popup
data-slot="alert-dialog-content"
className={cn(
"bg-background fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg transition-all duration-150 ease-out outline-none sm:max-w-lg",
"top-[calc(50%+1rem*var(--nested-dialogs))] scale-[calc(1-0.05*var(--nested-dialogs))] data-[ending-style]:top-[50.25%] data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:top-[50.25%] data-[starting-style]:scale-95 data-[starting-style]:opacity-0",
"data-[nested-dialog-open]:after:absolute data-[nested-dialog-open]:after:inset-0 data-[nested-dialog-open]:after:rounded-[inherit] data-[nested-dialog-open]:after:bg-black/5 data-[nested-dialog-open]:after:backdrop-blur-[1.5px]",
className
)}
{...props}
>
{children}
</AlertDialogPrimitive.Popup>
</AlertDialogPortal>
);
}
function AlertDialogHeader({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-dialog-header"
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
{...props}
/>
);
}
function AlertDialogFooter({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
data-slot="dialog-footer"
className={cn(
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
className
)}
{...props}
/>
);
}
function AlertDialogTitle({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
return (
<AlertDialogPrimitive.Title
data-slot="dialog-title"
className={cn("text-lg font-semibold", className)}
{...props}
/>
);
}
function AlertDialogDescription({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
return (
<AlertDialogPrimitive.Description
data-slot="dialog-description"
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
);
}
function AlertDialogClose({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Close>) {
return (
<AlertDialogPrimitive.Close
data-slot="alert-dialog-close"
className={cn(buttonVariants({ variant: "outline" }), className)}
{...props}
/>
);
}
export {
AlertDialog,
AlertDialogTrigger,
AlertDialogPortal,
AlertDialogBackdrop,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogClose,
};
Update the import paths to match your project setup.
Import all parts and piece them together.
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
<AlertDialog>
<AlertDialogTrigger>Open</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogTitle>Confirm Deletion</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to delete this item? This action cannot be undone.
</AlertDialogDescription>
<AlertDialogFooter>
<AlertDialogClose>Cancel</AlertDialogClose>
<Button>Delete</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
Examples
Close Confirmation
Open On Menu
In order to open a dialog using a menu, control the dialog state and open it imperatively using the onClick
handler on the menu item.
Return Focus Properly
Make sure to also use the dialog’s finalFocus
prop to return focus back
to the menu trigger.
import * as React from "react";
import {
AlertDialog,
AlertDialogContent,
AlertDialogDescription,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/component/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuPositioner,
DropdownMenuTrigger,
} from "@/component/ui/dropdown-menu";
export default function DropdownMenuRadio() {
const menuTriggerRef = React.useRef<HTMLButtonElement>(null);
const [alertDialogOpen, setAlertDialogOpen] = React.useState(false);
return (
<React.Fragment>
<DropdownMenu>
{/* Set the trigger ref */}
<DropdownMenuTrigger ref={menuTriggerRef}>Open</DropdownMenuTrigger>
<DropdownMenuPositioner>
<DropdownMenuContent>
{/* Open the dialog when the menu item is clicked */}
<DropdownMenuItem onClick={() => setAlertDialogOpen(true)}>
Open dialog
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenuPositioner>
</DropdownMenu>
{/* Control the dialog state */}
<AlertDialog open={alertDialogOpen} onOpenChange={setAlertDialogOpen}>
{/* Return focus to the menu trigger when the dialog is closed */}
<AlertDialogContent finalFocus={menuTriggerRef}>
<AlertDialogTitle>Are you sure you want to proceed?</AlertDialogTitle>
<AlertDialogDescription>
This action may have permanent effects. Please confirm if you want
to continue.
</AlertDialogDescription>
</AlertDialogContent>
</AlertDialog>
</React.Fragment>
);
}