Confirmation dialog
The safe workflow for an action that cannot be undone
State
Installation
npx shadcn@latest add @sudokw/components-confirm-dialogimport { ConfirmDialog } from "@gpuixui/components";Usage
import {
Alert,
AlertContent,
AlertDescription,
AlertTitle,
} from "@gpuixui/components/alert";
import { ConfirmDialog } from "@gpuixui/components/confirm-dialog";
import { Button } from "@gpuixui/primitives";
import { useState } from "react";
export const ArchiveProject = () => {
const [open, setOpen] = useState(false);
const [saving, setSaving] = useState(false);
const [error, setError] = useState<string | null>(null);
const archive = async () => {
setSaving(true);
setError(null);
try {
await archiveProject();
setOpen(false);
} catch {
setError("The workspace service timed out. Nothing was archived.");
} finally {
setSaving(false);
}
};
return (
<>
<Button variant="destructive" onClick={() => setOpen(true)}>
Archive project
</Button>
<ConfirmDialog
open={open}
onOpenChange={setOpen}
title="Archive this project?"
description="The project leaves everyone's sidebar. Its 18 open tasks stay attached and no files are deleted."
confirmLabel={error === null ? "Archive project" : "Try again"}
tone="danger"
loading={saving}
onConfirm={() => void archive()}
>
{error === null ? null : (
<Alert tone="danger">
<AlertContent>
<AlertTitle>Archive failed</AlertTitle>
<AlertDescription>{error}</AlertDescription>
</AlertContent>
</Alert>
)}
</ConfirmDialog>
</>
);
};Composition
ConfirmDialog
├── DialogContent
│ ├── DialogHeader
│ └── footer (actions)
└── childrenAPI reference
| Prop | Type | Default | Consequence |
|---|---|---|---|
open | boolean (required) | — | the controlled open state |
onOpenChange | (open: boolean) => void (required) | — | reports Cancel, Escape and an outside press |
title | string (required) | — | the dialog's accessible name and its heading |
description | string (required) | — | the consequence, as one paragraph |
confirmLabel | string | "Confirm" | the confirm action's label |
cancelLabel | string | "Cancel" | the cancel action's label |
tone | "default" | "danger" | "default" | "danger" paints the destructive action variant |
loading | boolean | false | disables both actions, paints the busy mark, and ignores Escape and an outside press |
onConfirm | () => void (required) | — | runs on activation; never closes the dialog |
children | ReactNode | — | extra body between the description and the actions |
Keyboard
- Escape
- cancels, unless a confirm is busy
- Tab
- keeps focus inside the dialog
Cancel is focused first; confirming reports and never closes.
read from modal.ts
Edit this page on GitHubapps/docs/content/docs/components/confirm-dialog.mdx