Overlays

ConfirmDialog

Modal-backed confirmation prompt with cancel and confirm actions, including a destructive variant for irreversible operations.

import { ConfirmDialog } from '@lostgradient/cinder/confirm-dialog';
overlaydialog
01

Overview

Pre-wired modal dialog for user-initiated binary decisions: "proceed" or "cancel". Focus defaults to the cancel button — the industry-standard guard against accidental destructive confirms.

See the dialog preset boundary for the preserved role, acknowledgement, and dismissal contract.

Dialog model

ConfirmDialog is one of three dialog-level components:

  • Modal — generic shell for rich content and forms. Use when the interaction requires more than two actions or rich body content.
  • ConfirmDialog — this component. Preset for user-initiated yes/no decisions. Escape, backdrop click, and the close-X all fire onCancel.
  • AlertDialog — preset for urgent blocking acknowledgements. Cannot be dismissed by Escape or backdrop click. No close button. The user must click an action button.

The key distinction between ConfirmDialog and AlertDialog is who initiates the interruption:

  • ConfirmDialog is for user-initiated actions that need a safety gate ("You clicked Delete — are you sure?"). Escape is a safe exit; cancel is the default focus.
  • AlertDialog is for system-initiated or out-of-band urgency ("Your session expired", "A background process failed"). Escape is blocked; acknowledgement is mandatory.

Choosing this component

  • Asking the user to confirm before deleting, discarding, or publishing something that cannot easily be undone.
  • Any two-action flow where the only choices are "proceed" and "cancel" — ConfirmDialog saves you from composing Modal + two Buttons manually.
  • Destructive actions: set destructive to apply the danger variant to the confirm button.

Choosing something else

  • When the dialog body needs rich content (lists, markup, multiple paragraphs) — compose Modal directly instead, since aria-describedby collapses to a single continuous string for screen readers.
  • When more than two actions are needed — use Modal with a custom footer snippet.
  • When the dialog is triggered by a system event or out-of-band condition requiring mandatory acknowledgement — use AlertDialog instead.
  • Non-blocking notifications — use a toast or inline alert that does not interrupt the flow.

Related components

  • Modal — the underlying primitive; use directly when you need more control over content or actions.
  • AlertDialog — sticky blocking acknowledgement; cannot be dismissed by Escape or backdrop click.

Usage

svelte
<script lang="ts">
  import Button from '@lostgradient/cinder/button';
  import ConfirmDialog from '@lostgradient/cinder/confirm-dialog';

  let open = $state(false);
  let triggerRef: HTMLElement | null = $state(null);
  let lastAction = $state('');
</script>

<div style="display: flex; flex-direction: column; gap: 1rem; align-items: flex-start;">
  <Button
    label="Delete item"
    variant="danger"
    onclick={(event: MouseEvent) => {
      triggerRef = event.currentTarget as HTMLElement;
      open = true;
    }}
  />

  {#if lastAction}
    <p style="margin: 0; color: var(--cinder-text-muted); font-size: var(--cinder-text-sm);">
      Last action: <strong>{lastAction}</strong>
    </p>
  {/if}
</div>

<ConfirmDialog
  bind:open
  {triggerRef}
  title="Delete item?"
  description="This permanently removes the item. This action cannot be undone."
  destructive
  confirmLabel="Delete"
  onConfirm={() => (lastAction = 'confirmed')}
  onCancel={() => (lastAction = 'cancelled')}
/>
Live preview
02

When to use

Use when
  • Requiring an explicit yes/no acknowledgement before performing a destructive or irreversible action.
  • Asking the user to confirm a discrete decision with two clear outcomes.
Avoid when
  • Collecting structured input or multiple fields — compose a modal with form controls instead.
  • Announcing a non-blocking result — use toast-region or banner.
03

Examples

Confirm dialog

A destructive action gated behind an explicit confirm and cancel prompt.

Delete account

A destructive ConfirmDialog for permanent account and data deletion. Default focus lands on Cancel to guard against accidental confirmation.

04

Props

Props for confirm-dialog
NameTypeDefaultDescription
open bindable boolean false Controls visibility. Bindable.
title required text Modal title; passed through to <Modal>.
description text Optional body description — short, plain text only. Rendered as a single <p> and wired to aria-describedby. For rich content (markup, lists, multiple paragraphs), compose <Modal> + <Button> directly — screen readers announce aria-describedby targets as one continuous run.
cancelLabel text 'Cancel' Label for the cancel button, which ALWAYS renders.
confirmLabel required text Confirm button label. Required — no default. Name the action being confirmed: - Destructive: "Delete", "Discard changes", "Remove from organization". - Non-destructive: "Save", "Continue", "Publish". Never use "OK" or "Confirm" in production — they don't describe the action.
destructive boolean false When true, the confirm button uses variant="danger". The cancel button still receives default focus regardless — color is never the sole destructive signal.
typeToConfirm text When set, renders a labelled text input and disables the confirm button until the trimmed input matches this value case-insensitively.
typeToConfirmLabel text Visible label for the typed-confirmation input. Defaults to Type "<value>" to confirm.
onConfirm required () => void Fired when the user activates the confirm button. Required. Component closes itself after.
onCancel () => void Called when the user cancels (cancel button, Escape, or backdrop per the dialog's policy).
triggerRef HTMLElement | null null Forwarded to <Modal>; focus is restored here on close.