modals /
Confirm / Destructive Dialog
Confirmation dialog for irreversible actions. Features a warning icon, loading state during deletion, and proper destructive button styling.
Preview
Source
tsx
"use client";
import { useState } from "react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
DialogTrigger,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Trash2, AlertTriangle } from "lucide-react";
export default function ConfirmDialog() {
const [open, setOpen] = useState(false);
const [deleting, setDeleting] = useState(false);
const [deleted, setDeleted] = useState(false);
function handleDelete() {
setDeleting(true);
setTimeout(() => {
setDeleting(false);
setDeleted(true);
setOpen(false);
}, 900);
}
return (
<div className="flex min-h-[200px] items-center justify-center p-8">
{deleted ? (
<div className="text-center space-y-2">
<p className="text-sm text-muted-foreground">Project deleted.</p>
<Button variant="outline" size="sm" onClick={() => setDeleted(false)}>
Reset demo
</Button>
</div>
) : (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="destructive" className="gap-2">
<Trash2 className="h-4 w-4" />
Delete project
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-sm">
<DialogHeader>
<div className="mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-full bg-red-100 text-red-600">
<AlertTriangle className="h-6 w-6" />
</div>
<DialogTitle className="text-center text-lg">Delete project?</DialogTitle>
<DialogDescription className="text-center text-sm">
This action <strong>cannot be undone</strong>. All data, files, and team
memberships associated with this project will be permanently removed.
</DialogDescription>
</DialogHeader>
<DialogFooter className="sm:flex-row gap-2 mt-2">
<Button
variant="outline"
className="flex-1"
onClick={() => setOpen(false)}
disabled={deleting}
>
Cancel
</Button>
<Button
variant="destructive"
className="flex-1 gap-2"
onClick={handleDelete}
disabled={deleting}
>
{deleting ? (
<>
<span className="h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" />
Deleting…
</>
) : (
<>
<Trash2 className="h-4 w-4" />
Yes, delete
</>
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)}
</div>
);
} Claude Code Instructions
CLI Install
npx innovations add confirmWhere to use it
Use this before any irreversible action: deleting records, cancelling subscriptions, removing team members, etc.
Pattern:
1. Wrap your trigger with <DialogTrigger asChild>
2. Show clear consequences in DialogDescription
3. Use Button variant="destructive" for the confirm action
4. Disable both buttons while the async operation is in progress
5. Close the dialog only after the async operation resolves
The AlertTriangle icon and red icon container communicate danger at a glance.