Overlays
Alert Dialog.
A modal that interrupts to confirm an important action. It does not close on outside click, so the reader has to choose.
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
export default function AlertDialogDemo() {
return (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Unpublish site</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Unpublish site?</AlertDialogTitle>
<AlertDialogDescription>
turtlewright.hub will disappear from the directory and visitors will see a dead link. Your pages and
guestbook stay saved on the server.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Keep it live</AlertDialogCancel>
<AlertDialogAction variant="destructive">Unpublish</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}Installation#
With the CLI
$npx lanterncn add alert-dialogThis also installs the Lantern theme and any Lantern UI components it depends on. The shadcn CLI works directly too: npx shadcn@latest add httptim/lantern-ui/alert-dialog. See Installation if your project is not set up yet.
Manually
Install the dependencies
npm install radix-uiCopy the source into your project
components/ui/alert-dialog.tsx"use client"; import * as React from "react"; import { AlertDialog as AlertDialogPrimitive } from "radix-ui"; 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 AlertDialogOverlay({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) { return ( <AlertDialogPrimitive.Overlay data-slot="alert-dialog-overlay" className={cn( "fixed inset-0 z-50 bg-[#080b0a]/75 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0", className, )} {...props} /> ); } function AlertDialogContent({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Content>) { return ( <AlertDialogPortal> <AlertDialogOverlay /> <AlertDialogPrimitive.Content data-slot="alert-dialog-content" className={cn( "fixed top-1/2 left-1/2 z-50 grid max-h-[calc(100dvh-2rem)] w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-5 overflow-y-auto rounded-lg border bg-popover p-6 text-popover-foreground shadow-block-sm duration-200 outline-none sm:max-w-md", "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", className, )} {...props} /> </AlertDialogPortal> ); } function AlertDialogHeader({ className, ...props }: React.ComponentProps<"div">) { return <div data-slot="alert-dialog-header" className={cn("flex flex-col gap-2 text-left", className)} {...props} />; } function AlertDialogFooter({ className, ...props }: React.ComponentProps<"div">) { return ( <div data-slot="alert-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="alert-dialog-title" className={cn("font-display text-xl leading-tight font-medium tracking-tight", className)} {...props} /> ); } function AlertDialogDescription({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Description>) { return ( <AlertDialogPrimitive.Description data-slot="alert-dialog-description" className={cn("text-sm leading-relaxed text-muted-foreground", className)} {...props} /> ); } function AlertDialogAction({ className, variant = "default", ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Action> & { variant?: "default" | "destructive"; }) { return ( <AlertDialogPrimitive.Action data-slot="alert-dialog-action" className={cn( buttonVariants({ variant: "default" }), variant === "destructive" && "bg-destructive text-destructive-foreground hover:bg-destructive/85", className, )} {...props} /> ); } function AlertDialogCancel({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) { return ( <AlertDialogPrimitive.Cancel data-slot="alert-dialog-cancel" className={cn(buttonVariants({ variant: "secondary" }), className)} {...props} /> ); } export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, };Update the import paths to match your project
The source imports
cnfrom@/lib/utilsand uses button.
Usage#
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogOverlay,
AlertDialogPortal,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Unpublish site</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Unpublish site?</AlertDialogTitle>
<AlertDialogDescription>Visitors will see a dead link.</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction variant="destructive">Unpublish</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>AlertDialogAction takes variant="destructive" for a filled red confirm button.