ProductBrand
Join us
Foundations
  • Introduction
  • Colors
  • Typography
  • Icons
  • Illustrations
  • Logos
  • Shadows
Components
  • Accordion
  • Alert Dialog
  • Avatar
  • Badge
  • Button
  • Calendar
  • Card
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Context Menu
  • Date Picker
  • Dialog
  • Drawer
  • Dropdown Menu
  • Fluid Avatar
  • Hover Scroll Text
  • Input
  • Kbd
  • Popover
  • Progress Bar
  • Radio Group
  • Scroll Area
  • Select
  • Selectors
  • Separator
  • Separator Dot
  • Shimmer Text
  • Skeleton
  • Slider
  • Switch
  • Tabs
  • Textarea
  • Toast
  • Tooltip
Compositions
  • Empty State
  • File Attachment
  • Floating Bar
  • Input Banner
  • Markdown Editor
  • Media Controls
  • Product Feature Banner
  • Panels
  • Sidebar
  • Reasoning Trace
  • Pagination
  • Data Table
  • Breadcrumb
  • Thread Outline
Inline
  • Overview
  • Stat Tile
  • Metric Row
  • Comparison Table
  • Chart Card
  • Trend Tile
  • Cite
  • Custom
  • Agent skill

Confirm Dialog

A packaged confirmation dialog for destructive and consequential actions. Every close produces exactly one outcome, and a deliberate cancel is reported separately from a dismissal.

Examples

Destructive

confirm 0 · cancel 0 · dismiss 0

Typed confirmation, consequences, and countdown

Overview

ConfirmDialog is opened imperatively through NiceModal: there is no trigger element to wire up, so any handler can raise it. It awaits onConfirm, showing a loading confirm button and refusing to close until the promise settles, and it also resolves the promise returned by show() with a boolean for callers that prefer await.

tsx
import { ConfirmDialog } from "@rogo-technologies/ui/confirm-dialog";
import { useModal } from "@rogo-technologies/ui/modal";

const modal = useModal(ConfirmDialog);

await modal.show({
  title: "Delete project?",
  description: "Members lose access immediately. This can't be undone.",
  confirmLabel: "Delete project",
  variant: "destructive",
  onConfirm: () => deleteProject(id),
});

Usage

Awaiting a boolean instead of passing callbacks

show() resolves true on confirm and false on cancel or dismissal, which reads well when the caller already owns the mutation and its error handling.

tsx
const confirmed = await modal.show({
  title: "Revoke this API client?",
  variant: "destructive",
  confirmLabel: "Revoke",
});
if (confirmed) revokeClient.mutate(clientId);

Cancel vs dismiss

onCancel fires only for the cancel button. Everything else that closes the dialog (the X, Escape, an outside press, a navigation that unmounts it, or a programmatic hide()) fires onDismiss. Use the split when "no" means something different from "not now": tell an analytics event or a "share all chats / only new chats" choice apart from walking away.

tsx
await modal.show({
  title: "Share existing chats with new members?",
  confirmLabel: "Share all chats",
  cancelLabel: "Only new chats",
  onConfirm: shareAll,
  onCancel: shareNewOnly,
  onDismiss: () => {},
});

Raising the stakes

Three opt-in props make a confirm harder to fire by accident. Reach for them when the action is unrecoverable and wide-reaching, not for routine deletes.

tsx
await modal.show({
  title: "Delete Acme Capital?",
  variant: "destructive",
  requireTypedConfirmation: "Acme Capital",
  consequences: ["Sign out all 412 members", "Delete 1,204 chats and their citations"],
  countdownSeconds: 3,
});

ConfirmDialog vs Alert Dialog

FeatureAlert DialogConfirm Dialog
CompositionCompound primitive you assembleOne packaged component, opened imperatively
TriggerAlertDialogTrigger in the markupAny handler, via useModal(ConfirmDialog).show()
Async confirmCaller's responsibilityAwaited, with a loading button and close blocked
OutcomesWhatever the caller wires upExactly one of confirm / cancel / dismiss
Use caseBespoke confirmation layoutsThe standard destructive or consequential decision

API

PropTypeDefaultDescription
titlestring-Required. Say what is about to happen.
descriptionstring-Supporting copy under the title.
confirmLabelstring"Confirm"Label of the confirm button.
cancelLabelstring"Cancel"Label of the cancel button.
variantConfirmDialogVariant"default"default (no icon), info, warning, or destructive. Also picks the icon and confirm button treatment.
consequencesstring[]-Spelled-out effects of confirming.
requireTypedConfirmationstring-Confirm stays disabled until the user types this string exactly.
countdownSecondsnumber-Confirm stays disabled for this many seconds after opening.
onConfirm() => void | Promise<void>-Awaited. The confirm button shows a loading state and the dialog refuses to close.
onCancel() => void-The cancel button only.
onDismiss() => void-X, Escape, outside press, navigation, or a programmatic hide.

ConfirmDialogContent is also exported for hosts that need to supply their own Modal root: apps/frontend uses it so that its router-aware root still closes the dialog on a route change.

Guidelines

Do

  • Name the operation in the confirm label ("Delete project", not "OK")
  • Pass variant="destructive" when the action can't be undone
  • Let onConfirm be async and let the dialog own the loading state
  • Use requireTypedConfirmation for tenant-wide or organization-wide deletions

Don't

  • Don't confirm routine, reversible actions. Offer an undo instead
  • Don't add countdownSeconds to anything a user does more than rarely; it reads as a punishment
  • Don't treat a dismissal as a cancel when the two mean different things to your caller
  • Don't hand-roll another confirmation modal. Extend this one

Design at Rogo

We’re redesigning an entire industry. Come design it with us.

See open roles

Design at Rogo

  • How we workThe mission of design at Rogo, and the open roles
  • About RogoThe company and the product