Alert Dialog
A dialog that requires user response to proceed. Built with Base UI and Tailwind CSS. Copy-paste ready.
import {
AlertDialog,
AlertDialogClose,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogPopup,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
export default function Particle() {
return (
<AlertDialog>
<AlertDialogTrigger render={<Button variant="destructive-outline" />}>
Delete Account
</AlertDialogTrigger>
<AlertDialogPopup>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete your
account and remove your data from our servers.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogClose render={<Button variant="ghost" />}>
Cancel
</AlertDialogClose>
<AlertDialogClose render={<Button variant="destructive" />}>
Delete Account
</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogPopup>
</AlertDialog>
);
}
Installation
pnpm dlx shadcn@latest add @cnippet/alert-dialog
Usage
import {
AlertDialog,
AlertDialogClose,
AlertDialogDescription,
AlertDialogPanel,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogPopup,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"<AlertDialog>
<AlertDialogTrigger>Delete Account</AlertDialogTrigger>
<AlertDialogPopup>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogPanel>Content</AlertDialogPanel>
<AlertDialogFooter>
<AlertDialogClose>Cancel</AlertDialogClose>
<AlertDialogClose>Delete Account</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogPopup>
</AlertDialog>AlertDialogFooter Variant
The AlertDialogFooter component supports a variant prop to control its styling:
default(default): Includes a border-top, background color, and paddingbare: Removes the border and background for a minimal appearance
// Default variant (with border and background)
<AlertDialogFooter>
<AlertDialogClose>Cancel</AlertDialogClose>
<AlertDialogClose>Delete</AlertDialogClose>
</AlertDialogFooter>
// Bare variant (no border or background)
<AlertDialogFooter variant="bare">
<AlertDialogClose>Cancel</AlertDialogClose>
<AlertDialogClose>Delete</AlertDialogClose>
</AlertDialogFooter>Examples
Small Size
A compact alert dialog with a smaller popup size, suitable for brief single-action confirmations.
import { BluetoothIcon } from "lucide-react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="outline">Small (Media)</Button>}
/>
<AlertDialogContent className="max-w-xs">
<AlertDialogHeader>
<div className="flex size-12 items-center justify-center rounded-full border bg-muted text-foreground [&_svg]:size-6">
<BluetoothIcon />
</div>
<AlertDialogTitle>Allow accessory to connect?</AlertDialogTitle>
<AlertDialogDescription>
Do you want to allow the USB accessory to connect to this device?
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogClose render={<Button variant="outline" />}>
Don't allow
</AlertDialogClose>
<AlertDialogClose render={<Button />}>Allow</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
Nested In Dialog
Nests an alert dialog trigger inside an open dialog to demonstrate stacked overlay behavior with correct focus management.
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
export function Pattern() {
return (
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
Open Dialog
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Alert Dialog Example</DialogTitle>
<DialogDescription>
Click the button below to open an alert dialog.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<AlertDialog>
<AlertDialogTrigger render={<Button />}>
Open Alert Dialog
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete
your account and remove your data from our servers.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogClose render={<Button variant="ghost" />}>
Cancel
</AlertDialogClose>
<AlertDialogClose render={<Button />}>
Continue
</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
Task Success Confirmation
A success-state dialog confirming a completed action with a checkmark icon and a single dismiss button.
import { CheckIcon } from "lucide-react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="outline">Task Status</Button>}
/>
<AlertDialogContent>
<div className="flex items-center gap-3 p-4">
<div className="flex size-10 items-center justify-center rounded-full bg-emerald-50 text-emerald-500 dark:bg-emerald-950 dark:text-emerald-300">
<CheckIcon className="size-5" />
</div>
<div className="flex flex-col justify-center gap-1">
<AlertDialogTitle className="font-semibold text-sm">
Task successful
</AlertDialogTitle>
<AlertDialogDescription className="text-muted-foreground text-sm">
Your task has been completed successfully.
</AlertDialogDescription>
</div>
</div>
<AlertDialogFooter className="items-center gap-4 sm:justify-between">
<div className="flex items-center gap-2">
<Checkbox id="show-again" />
<Label
className="font-normal text-muted-foreground"
htmlFor="show-again"
>
Don't show again
</Label>
</div>
<div className="flex items-center gap-2">
<AlertDialogClose render={<Button variant="ghost" />}>
Cancel
</AlertDialogClose>
<AlertDialogClose render={<Button />}>Confirm</AlertDialogClose>
</div>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
Account Deactivation
A destructive confirmation dialog for deactivating an account, requiring the user to type the account name before proceeding.
import { CircleAlertIcon } from "lucide-react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="destructive">Deactivate Account</Button>}
/>
<AlertDialogContent>
<div className="flex items-start gap-3 p-4">
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-destructive/10 dark:bg-destructive/10">
<CircleAlertIcon className="size-5 text-destructive" />
</div>
<div className="flex flex-col justify-center gap-1">
<AlertDialogTitle className="font-semibold text-sm">
Deactivate your account?
</AlertDialogTitle>
<AlertDialogDescription className="text-muted-foreground text-sm">
This will disable your account and remove your profile from all
active searches.
</AlertDialogDescription>
</div>
</div>
<AlertDialogFooter>
<AlertDialogClose render={<Button variant="ghost" />}>
Keep My Account
</AlertDialogClose>
<AlertDialogClose render={<Button variant="destructive" />}>
Deactivate Anyway
</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
Unsaved Changes
Warns the user that navigating away will discard unsaved changes, with options to cancel or confirm the discard.
import { CardSimIcon } from "lucide-react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Frame, FramePanel } from "@/components/ui/frame";
import { Label } from "@/components/ui/label";
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="outline">Discard Changes</Button>}
/>
<AlertDialogContent className="overflow-hidden p-0! ring-0">
<Frame className="p-px">
<FramePanel className="p-0">
<div className="flex items-start gap-3 p-4">
<div className="flex size-10 shrink-0 items-center justify-center rounded-full border border-amber-100 bg-amber-50 text-amber-500 dark:bg-amber-950 dark:text-amber-300">
<CardSimIcon className="size-5" />
</div>
<div className="flex flex-col justify-center gap-1">
<AlertDialogTitle className="font-semibold text-sm">
Unsaved changes
</AlertDialogTitle>
<AlertDialogDescription className="text-muted-foreground text-sm">
You have unsaved changes in this form. If you leave now, your
progress will be lost.
</AlertDialogDescription>
</div>
</div>
<AlertDialogFooter className="mt-2 items-center gap-4 sm:justify-between">
<div className="flex items-center gap-2">
<Checkbox id="dont-ask-again" />
<Label
className="font-normal text-muted-foreground"
htmlFor="dont-ask-again"
>
Don't ask again
</Label>
</div>
<div className="flex items-center gap-2">
<AlertDialogClose render={<Button variant="ghost" />}>
Stay
</AlertDialogClose>
<AlertDialogClose render={<Button />}>
Discard Changes
</AlertDialogClose>
</div>
</AlertDialogFooter>
</FramePanel>
</Frame>
</AlertDialogContent>
</AlertDialog>
);
}
Ticket Registration
A success dialog confirming ticket registration details with event information and a dismiss or download action.
import { CheckIcon } from "lucide-react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="outline">View Confirmation</Button>}
/>
<AlertDialogContent className="gap-8 p-0 sm:max-w-sm">
<div className="mx-auto flex flex-col items-center justify-center gap-2 p-4">
<div className="flex size-16 items-center justify-center rounded-full bg-info/10 text-info dark:bg-info/20">
<CheckIcon className="size-5" />
</div>
<AlertDialogTitle className="text-center">
Success! Your e-ticket is registered.
</AlertDialogTitle>
<AlertDialogDescription className="max-w-xs text-center">
Please check your email for confirmation and further instructions
about the event.
</AlertDialogDescription>
</div>
<div className="m-4 grid gap-4 rounded-xl bg-muted/60 p-4">
{[
["Order Number", "GBD99763JS"],
["Order Date", "7 September 2024"],
["Event Name", "Groove Beats Day Fest"],
["Event Date", "20/09/2024"],
["Register Date", "20/09/2024 | 09 PM"],
].map(([label, value]) => (
<div
className="flex items-center justify-between text-sm"
key={label}
>
<span className="font-medium text-muted-foreground">{label}</span>
<span className="font-semibold text-foreground">{value}</span>
</div>
))}
</div>
<AlertDialogFooter>
<AlertDialogClose
render={<Button className="w-full sm:w-full" size="lg" />}
>
Back to Home
</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
System Update Notification
Notifies the user of a pending system update with options to install now or postpone to a later time.
import { ShieldAlertIcon } from "lucide-react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="outline">System Update</Button>}
/>
<AlertDialogContent className="gap-0 p-0 sm:max-w-sm">
<div className="mx-auto flex flex-col items-center justify-center gap-2 p-8">
<div className="flex size-12 items-center justify-center rounded-full bg-info/10 text-info dark:bg-info/20">
<ShieldAlertIcon className="size-6" />
</div>
<AlertDialogTitle className="text-center">
System Update Available!
</AlertDialogTitle>
<Badge variant="success">Release v28.1.0 (2026-01-12)</Badge>
</div>
<div className="flex flex-col items-center justify-center gap-5 rounded-b-2xl bg-muted/60 pt-6">
<AlertDialogDescription className="px-6 text-center text-muted-foreground">
A new version of the application is ready. Restarting now will apply
the latest security patches and features.
</AlertDialogDescription>
<AlertDialogFooter className="flex w-full gap-4 sm:items-center sm:justify-center">
<AlertDialogClose render={<Button variant="ghost" />}>
Remind Me Later
</AlertDialogClose>
<AlertDialogClose render={<Button />}>Update Now</AlertDialogClose>
</AlertDialogFooter>
</div>
</AlertDialogContent>
</AlertDialog>
);
}
Expired Subscription
An alert informing the user that their subscription has expired, with a direct link to the billing renewal page.
import { BellIcon } from "lucide-react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="outline">Subscription Expiring</Button>}
/>
<AlertDialogContent className="gap-0 p-0 sm:max-w-sm">
<div className="mx-auto flex flex-col items-center justify-center gap-2 p-8">
<div className="flex size-12 items-center justify-center rounded-full bg-destructive/10 text-destructive dark:bg-destructive/20">
<BellIcon className="size-6" />
</div>
<AlertDialogTitle className="text-center">
Subscription Expiring Soon
</AlertDialogTitle>
<Badge className="font-normal" variant="destructive">
Expires in 2 days
</Badge>
</div>
<div className="flex flex-col items-center justify-center gap-5 rounded-b-2xl bg-muted/60 pt-6">
<AlertDialogDescription className="px-6 text-center text-muted-foreground">
Your current plan will expire in 2 days. Update your payment method
now to ensure uninterrupted access to your Pro features.
</AlertDialogDescription>
<AlertDialogFooter className="w-full gap-4">
<AlertDialogClose render={<Button variant="ghost" />}>
Remind Me Later
</AlertDialogClose>
<AlertDialogClose render={<Button />}>
Update Payment
</AlertDialogClose>
</AlertDialogFooter>
</div>
</AlertDialogContent>
</AlertDialog>
);
}
Logout Confirmation
Asks the user to confirm their intent to log out before the session is ended.
import { ShieldQuestionMarkIcon } from "lucide-react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger render={<Button variant="outline">Logout</Button>} />
<AlertDialogContent className="gap-0 overflow-hidden p-0 sm:max-w-sm">
<div className="flex flex-col items-center justify-center gap-2 p-8">
<div className="flex size-12 items-center justify-center rounded-full bg-violet-50 text-violet-500 dark:bg-violet-950 dark:text-violet-400">
<ShieldQuestionMarkIcon className="size-6" />
</div>
<AlertDialogTitle className="text-center font-semibold text-base">
Are you sure?
</AlertDialogTitle>
<AlertDialogDescription className="p-0 text-center font-medium text-sm">
You can always log in later to your account.
</AlertDialogDescription>
</div>
<AlertDialogFooter className="grid w-full flex-none grid-cols-2 gap-0 divide-x border-t py-0">
<AlertDialogClose
render={
<Button
className="h-12 flex-1 rounded-none border-0 border-border border-r p-0"
variant="ghost"
/>
}
>
No
</AlertDialogClose>
<AlertDialogClose
render={
<Button
className="h-12 flex-1 rounded-none border-0 p-0"
variant="ghost"
/>
}
>
Yes, Logout
</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
File Overwrite Confirmation
A three-button dialog that appears when uploading a file that already exists — letting the user choose to keep both copies, skip the upload, or replace the existing file.
import { FileIcon } from "lucide-react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="outline">Upload File</Button>}
/>
<AlertDialogContent className="sm:max-w-sm">
<div className="flex items-start gap-3 p-4">
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-muted">
<FileIcon className="size-5 text-muted-foreground" />
</div>
<div className="flex flex-col gap-1">
<AlertDialogTitle className="font-semibold text-sm">
File already exists
</AlertDialogTitle>
<AlertDialogDescription className="text-muted-foreground text-sm">
<strong className="text-foreground">design-system-v2.fig</strong>{" "}
(48 MB) already exists in{" "}
<span className="font-mono text-xs">/Projects/Design</span>. Do
you want to replace it?
</AlertDialogDescription>
</div>
</div>
<AlertDialogFooter>
<AlertDialogClose render={<Button variant="ghost" />}>
Keep Both
</AlertDialogClose>
<AlertDialogClose render={<Button variant="outline" />}>
Skip
</AlertDialogClose>
<AlertDialogClose render={<Button />}>Replace</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
Subscription Downgrade Warning
Displays a bulleted list of Pro features the user will lose if they confirm the downgrade, making the consequence of the action explicit before they proceed.
import { TrendingDownIcon } from "lucide-react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
const lostFeatures = [
"Unlimited team members",
"Custom domain support",
"Priority support (24h SLA)",
"Advanced analytics dashboard",
"SSO & SAML integration",
];
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="outline">Downgrade to Free</Button>}
/>
<AlertDialogContent className="sm:max-w-md">
<div className="flex items-start gap-3 p-4">
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-destructive/10">
<TrendingDownIcon className="size-5 text-destructive" />
</div>
<div>
<AlertDialogTitle className="font-semibold text-sm">
Downgrade to Free plan?
</AlertDialogTitle>
<AlertDialogDescription className="mt-1 text-muted-foreground text-sm">
You'll lose access to the following features at the end of
your billing period:
</AlertDialogDescription>
</div>
</div>
<ul className="mx-4 mb-4 space-y-1.5 rounded-lg border bg-muted/50 p-3">
{lostFeatures.map((f) => (
<li
className="flex items-center gap-2 text-muted-foreground text-sm"
key={f}
>
<span className="size-1.5 shrink-0 rounded-full bg-destructive" />
{f}
</li>
))}
</ul>
<AlertDialogFooter>
<AlertDialogClose render={<Button variant="ghost" />}>
Keep Pro
</AlertDialogClose>
<AlertDialogClose render={<Button variant="destructive" />}>
Downgrade Anyway
</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
Transfer Ownership
A typed-confirmation dialog that requires the user to enter the word "transfer" before the destructive button becomes enabled, preventing accidental ownership changes.
"use client";
import { KeyRoundIcon } from "lucide-react";
import { useState } from "react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
const CONFIRM_TEXT = "transfer";
export function Pattern() {
const [value, setValue] = useState("");
const confirmed = value === CONFIRM_TEXT;
return (
<AlertDialog onOpenChange={(open) => !open && setValue("")}>
<AlertDialogTrigger
render={
<Button variant="destructive-outline">Transfer Ownership</Button>
}
/>
<AlertDialogContent className="sm:max-w-sm">
<div className="flex items-start gap-3 p-4">
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-amber-50 dark:bg-amber-950">
<KeyRoundIcon className="size-5 text-amber-600 dark:text-amber-400" />
</div>
<div className="flex flex-col gap-1">
<AlertDialogTitle className="font-semibold text-sm">
Transfer organization ownership
</AlertDialogTitle>
<AlertDialogDescription className="text-muted-foreground text-sm">
This transfers full ownership to another member. You will lose
admin privileges immediately and cannot undo this.
</AlertDialogDescription>
</div>
</div>
<div className="mx-4 mb-4 flex flex-col gap-2">
<Label className="text-sm" htmlFor="confirm-transfer">
Type <span className="font-mono font-semibold">{CONFIRM_TEXT}</span>{" "}
to confirm
</Label>
<Input
id="confirm-transfer"
onChange={(e) => setValue(e.target.value)}
placeholder={CONFIRM_TEXT}
value={value}
/>
</div>
<AlertDialogFooter>
<AlertDialogClose render={<Button variant="ghost" />}>
Cancel
</AlertDialogClose>
<AlertDialogClose
render={<Button disabled={!confirmed} variant="destructive" />}
>
Transfer Ownership
</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
Clear All Data
A checkbox consent gate that must be checked before the Delete button activates. The checkbox and button state both reset when the dialog is dismissed without confirming.
"use client";
import { Trash2Icon } from "lucide-react";
import { useState } from "react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
export function Pattern() {
const [agreed, setAgreed] = useState(false);
return (
<AlertDialog onOpenChange={(open) => !open && setAgreed(false)}>
<AlertDialogTrigger
render={<Button variant="destructive">Clear All Data</Button>}
/>
<AlertDialogContent className="sm:max-w-sm">
<div className="flex flex-col items-center gap-3 p-6 pb-4">
<div className="flex size-12 items-center justify-center rounded-full bg-destructive/10">
<Trash2Icon className="size-5 text-destructive" />
</div>
<AlertDialogTitle className="text-center font-semibold">
Clear all workspace data?
</AlertDialogTitle>
<AlertDialogDescription className="text-center text-muted-foreground text-sm">
This permanently deletes all projects, files, members, and settings.
This action is irreversible and cannot be undone.
</AlertDialogDescription>
</div>
<div className="mx-6 mb-4 flex items-start gap-2 rounded-lg border border-destructive/20 bg-destructive/5 p-3">
<Checkbox
checked={agreed}
id="clear-confirm"
onCheckedChange={(v) => setAgreed(Boolean(v))}
/>
<Label
className="cursor-pointer text-muted-foreground text-sm leading-snug"
htmlFor="clear-confirm"
>
I understand this will permanently delete all data and cannot be
recovered.
</Label>
</div>
<AlertDialogFooter>
<AlertDialogClose render={<Button variant="ghost" />}>
Cancel
</AlertDialogClose>
<AlertDialogClose
render={<Button disabled={!agreed} variant="destructive" />}
>
Delete Everything
</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
Rate Limit Exceeded
Shows a live countdown timer indicating when the user may retry. Uses a nested Countdown component driven by useEffect to decrement the displayed time each second.
"use client";
import { TimerIcon, ZapIcon } from "lucide-react";
import { useEffect, useState } from "react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
function Countdown({ seconds }: { seconds: number }) {
const [left, setLeft] = useState(seconds);
useEffect(() => {
if (left <= 0) return;
const t = setTimeout(() => setLeft((l) => l - 1), 1000);
return () => clearTimeout(t);
}, [left]);
const m = Math.floor(left / 60)
.toString()
.padStart(2, "0");
const s = (left % 60).toString().padStart(2, "0");
return (
<span className="font-mono font-semibold text-foreground">
{m}:{s}
</span>
);
}
export function Pattern() {
return (
<AlertDialog>
<AlertDialogTrigger render={<Button>Make API Request</Button>} />
<AlertDialogContent className="sm:max-w-sm">
<div className="flex flex-col items-center gap-3 p-6 pb-4">
<div className="flex size-12 items-center justify-center rounded-full bg-amber-50 dark:bg-amber-950">
<ZapIcon className="size-5 text-amber-600 dark:text-amber-400" />
</div>
<AlertDialogTitle className="text-center font-semibold text-base">
Rate limit exceeded
</AlertDialogTitle>
<AlertDialogDescription className="text-center text-muted-foreground text-sm">
You've reached the limit of 100 requests per minute. Retry
automatically in:
</AlertDialogDescription>
<div className="flex items-center gap-2 rounded-lg border bg-muted/60 px-4 py-2 text-sm">
<TimerIcon className="size-4 text-muted-foreground" />
<Countdown seconds={90} />
</div>
<p className="text-center text-muted-foreground text-xs">
Upgrade to Pro for a 10× higher rate limit.
</p>
</div>
<AlertDialogFooter className="px-6 pb-6">
<AlertDialogClose
render={<Button className="flex-1" variant="outline" />}
>
Dismiss
</AlertDialogClose>
<AlertDialogClose render={<Button className="flex-1" />}>
Upgrade to Pro
</AlertDialogClose>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
On This Page

