Skip to main content
Urbicon UI
source

ConfirmDialog

Pre-configured dialog for confirming a single, often destructive action: a styleable, focus-trapped replacement for window.confirm().

Playground

<script lang="ts">
  import { ConfirmDialog } from '@urbicon-ui/blocks';

  let open = $state(false);
</script>

<ConfirmDialog
  bind:open
  cancelLabel="Cancel"
  confirmLabel="Delete"
  description="This cannot be undone."
  intent="danger"
  title="Delete project?"
/>

01 Examples

Destructive confirmation

bind:open drives visibility. onConfirm runs the action and the dialog closes itself. onCancel runs on cancel, backdrop click, or Escape.
<script>
  let confirmOpen = $state(false);
</script>
<Button intent="danger" onclick={() => (confirmOpen = true)}>Delete</Button>
<ConfirmDialog
  bind:open={confirmOpen}
  title="Delete project?"
  description="This cannot be undone."
  intent="danger"
  confirmLabel="Delete"
  onConfirm={() => deleteProject()}
/>

Async onConfirm

When onConfirm returns a promise the dialog disables both buttons, blocks dismissal, shows a spinner on the confirm button, then auto-closes on success. If the promise rejects the dialog stays open and re-enables for a retry. Surface the failure via onError.
<ConfirmDialog
  bind:open
  title="Submit report?"
  description="Network call may take a moment."
  intent="primary"
  confirmLabel="Submit"
  onConfirm={async () => { await api.submit(); }}
  onError={() => toaster.danger('Could not submit report')}
/>

02 Customization

Accented panel

slotClasses reaches through to the inner Dialog. Giving the panel slot an opaque surface token plus a primary border keeps the body text at full contrast, while the primary intent already tints the title and confirm button. The panel's radius tier, centering and focus trap stay intact.
<ConfirmDialog
  bind:open
  title="Publish release?"
  description="Version 2.0 goes live for everyone."
  intent="primary"
  confirmLabel="Publish"
  slotClasses={{ panel: 'bg-surface-elevated border-primary' }}
/>

intent reaches both halves of the dialog, but not in the same way: it tints the header title for every value except neutral, which leaves the header in the resting tone, and it is what the confirm button wears — neutral included, so a neutral dialog gets a filled neutral confirm button, because the accent belongs to the primary action rather than to every confirmation. Put the accent back with confirmIntent="primary", which overrides the button alone. For a richer body (a list of consequences, a typed-confirmation field) pass a children snippet, which renders below the description.

ConfirmDialog is a pre-configured Dialog and owns no styles, so class, unstyled, slotClasses and preset forward to it verbatim. Its slotClasses takes the Dialog slot keys, and a preset registered under the Dialog key restyles both.

This is one of five ways to restyle a block. See Customization for class, slotClasses, unstyled, preset and provider-level overrides.

03 Accessibility

Inherited from Dialog

Focus trap, Escape-to-cancel and backdrop-click-to-cancel all come from the underlying Dialog. While an async onConfirm is pending, Escape and backdrop dismissal are disabled and the close button is hidden, so the user cannot dismiss the dialog mid-action. The focus trap stays active throughout.

Real buttons

Cancel and confirm are actual <button> elements, so keyboard navigation (Tab, Enter, Space) works without extra wiring.

Translatable labels

Default labels resolve via bt('button.confirm') / bt('button.cancel'). Translate them through the i18n package, or override per call via confirmLabel / cancelLabel.

04 API Reference

21 props
21 props 1 required
Prop
Type
Default
Description

05 Types

Local type definitions used by this component.

7 types
Name
Kind
Category
Used by
Description

06 Installation

Import

import { ConfirmDialog } from '@urbicon-ui/blocks';