# Confirm dialog (goodtabs UI)

Asks one question before an action, with a pending state for async confirms.

## Install

```bash
npx shadcn@latest add https://ui.goodtabs.co/r/confirm-dialog.json
```

Or, with the @goodtabs namespace configured in components.json: `npx shadcn@latest add @goodtabs/confirm-dialog`

## Usage

```tsx
import { ConfirmDialog } from "@/components/ui/confirm-dialog"

<ConfirmDialog
  variant="destructive"
  title="Delete this project?"
  description="There is no undo."
  confirmLabel="Delete"
  onConfirm={async () => { await deleteProject(id) }}
>
  <Button variant="destructive">Delete</Button>
</ConfirmDialog>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| children | `ReactNode` |  | The trigger element, rendered with asChild. |
| title | `string` |  | The question, as a short sentence. |
| description | `string` |  | What happens if they confirm. |
| confirmLabel | `string` | `"Confirm"` | Label of the confirm button. |
| cancelLabel | `string` | `"Cancel"` | Label of the cancel button. |
| variant | `"default" | "destructive"` | `"default"` | Destructive styles the confirm button for actions with no undo. |
| onConfirm | `() => void | Promise<void>` |  | Runs on confirm. A promise shows a pending state until it settles. |
| open | `boolean` |  | Controlled open state. |
| onOpenChange | `(open: boolean) => void` |  | Fires when the dialog asks to open or close. |

## When to use

- Before an action that cannot be undone: delete, publish, send, pay
- When a click would affect other people or cost money
- Any confirm that calls a server and needs a pending state

## When not to use

- Routine actions that are easy to reverse: offer undo in a toast instead
- Collecting input: use a Dialog with a form, not an alert dialog

## Notes for agents

- onConfirm is a function, so the component that renders ConfirmDialog must be a client component ("use client")
- Built on shadcn's AlertDialog, so it traps focus and ignores clicks outside by design
- Pass a Button as children and it becomes the trigger; omit children and control it with open
- While onConfirm is pending, Escape, cancel and confirm are all disabled
- If onConfirm throws, the dialog stays open and pending clears; handle the error where you call it

Docs: https://ui.goodtabs.co/components/confirm-dialog