Skip to content

ConfirmDialog

Purpose

ConfirmDialog is the shared UI for confirmations. It is intentionally “dumb”:

  • It renders a dialog using Radix AlertDialog primitives
  • It receives configuration via ConfirmOptions
  • It relies on useConfirmation to provide the open state and promise-based control flow

When to use

Use ConfirmDialog when:

  • You want consistent confirmation UI across the app
  • You want async control flow (await confirm(...)) rather than callback nesting

Don’t embed confirmation logic inside the dialog. Keep logic in useConfirmation.

Example

tsx
import React from 'react'
import { useConfirmation } from '@/shared/hooks'
import { ConfirmDialog } from '@/shared/ui/components/ConfirmDialog'

export function DeleteThingButton() {
  const { state, confirm, handleConfirm, handleCancel } = useConfirmation()

  const onDelete = async () => {
    const ok = await confirm({
      title: 'Delete item?',
      description: 'This action cannot be undone.',
      confirmLabel: 'Delete',
      cancelLabel: 'Cancel',
      variant: 'destructive',
    })

    if (!ok) return

    // await repository.deleteThing()
  }

  return (
    <>
      <button type="button" onClick={onDelete}>Delete</button>

      <ConfirmDialog
        open={state.isOpen}
        options={state.options}
        onConfirm={handleConfirm}
        onCancel={handleCancel}
      />
    </>
  )
}

Props (concise)

  • open: boolean
    • Whether the dialog is visible.
  • options: ConfirmOptions | null
    • Configuration for the dialog.
    • ConfirmOptions supports: title, description?, confirmLabel?, cancelLabel?, variant?: 'default' | 'destructive'.
  • onConfirm()
    • Called when the user confirms.
  • onCancel()
    • Called when the user cancels, or when the dialog is dismissed.

Notes / Gotchas

  • Always render one instance: treat ConfirmDialog like an app/page-level portal for confirmations, driven by useConfirmation state.
  • options === null: the component returns null if options is missing; ensure you pass state.options from the hook.
  • Dismiss behavior: closing the dialog triggers cancel logic so confirm(...) resolves false.