--- ## Dialog Overlay dialog built on native dialog element. Can be used as a simple content-agnostic overlay or as a structured dialog with title, optional header icon and footer. `intent` tints the header markers (title, icon) and is exposed as `data-intent` on the panel; the panel surface itself stays neutral, because a tinted surface under a consumer's form or table would hijack that content's contrast ratios. **Import:** `import { Dialog } from '@urbicon-ui/blocks';` ### Examples ```svelte

Are you sure?

``` ```svelte

This action cannot be undone.

{#snippet footer()} {/snippet}
``` ### Variants - intent: danger, neutral, primary, secondary, success, warning (default: neutral) - size: full, fullscreen, lg, md, sm, xl (default: sm) - placement: center, top (default: center) - center — Mobile keeps the bottom-sheet alignment so a swipe-up gesture hits the bottom edge; desktop opens centered. ### Api | Prop | Type | Required | Default | Description | | --- | --- | :---: | --- | --- | | children | `Snippet` | yes | | Dialog body content. When `title` is omitted the content fills the entire panel. | | ...HTMLDialogAttributes | `HTMLAttributes` | no | | HTML attributes (excluding: 'children' | 'open' | 'draggable') | | class | `string` | no | | Additional CSS classes applied to the dialog panel. In the same Tailwind bucket `class` wins over the `slotClasses` entry for the element it lands on. Presets and provider defaults sit below both. | | closeOnBackdropClick | `boolean` | no | true | Whether clicking the backdrop dismisses the dialog. Turning this off together with `closeOnEscape` and `hideCloseButton` is a legitimate pattern for a forced choice (terms to accept, data loss to confirm, an expired session) — but only when the dialog itself renders the action that resolves it. Without one there is no way out, and DEV warns. | | closeOnEscape | `boolean` | no | true | Whether pressing Escape dismisses the dialog. The ARIA APG recommends Escape and does not forbid disabling it; the same condition as `closeOnBackdropClick` applies — with every exit closed, the dialog must carry its own action. Escape is dismissed one layer at a time: a control INSIDE the dialog that handles Escape itself — an open `Select`/`Combobox`/`Menu` panel, an open `Popover` wherever focus sits, a `clearable` `Input` with text in it — consumes the key, and the dialog stays up. The second Escape closes the dialog. This is about controls in the content; it does not apply to a consumer `onkeydown` on the Dialog itself, which cannot veto the dismiss (see utils/compose-handlers.ts) — use this prop for that. | | draggable | `boolean` | no | false | Let the user reposition the dialog by dragging its header. Off by default. The structured header (rendered when `title` is set) becomes the drag handle; the close button and any header controls stay clickable, and the offset resets each time the dialog reopens. Most useful for a dialog the user may want to shove aside to see the content behind it. Requires a `title` — without a header there is nothing to grab. Overrides the native HTML `draggable` attribute, which has no meaningful use on a dialog. | | footer | `Snippet` | no | | Action buttons rendered in a footer bar. Only rendered when provided. | | hideCloseButton | `boolean` | no | false | Hides the built-in close button. Only takes effect when `title` is also set — the close button only renders in the structured (titled) header. Without a title, no close button exists to hide. The last of the three exits; see `closeOnBackdropClick` for what closing all of them requires. | | icon | `Snippet` | no | | Icon rendered before the title in the header bar. Takes its colour from `intent`, so a bare icon component is enough — no wrapper needed. Marked `aria-hidden`: it repeats the intent the title already carries in words. Requires `title` (no header renders without one). | | intent | `DialogVariants['intent']` | no | 'neutral' | Semantic purpose marker (e.g. `danger` for destructive actions). Tints the header markers — the title and, when given, `icon`. The panel surface stays neutral by design: this is a container for arbitrary content, and a tinted surface would hijack the contrast ratios of the form, table or code block inside it (the Toast makes the same split). The value is additionally exposed on the panel as `data-intent="…"` for presets and CSS overrides. | | onClose | `() => void` | no | | Fires when a close of the dialog is requested — Escape, a backdrop click, the close button, `overlayStack.closeAll()` or `closeTop()` — before the exit animation, while focus is still inside. `open` is already `false` when it runs, and writing `open = true` back synchronously inside it vetoes the close: the dialog stays open, plays no exit, keeps focus and never reaches `onClosed`. A close the browser performs itself also arrives here, after the `` has closed, and cannot be vetoed — a `
`, a call to `close()`, or a close request the dialog did not intercept (a back gesture, assistive technology); the dialog stays closed and DEV warns. `closeOnEscape={false}` holds such requests off for as long as the browser lets a page refuse them. Not fired when you set `open = false` yourself. | | onClosed | `() => void` | no | | Fires once a close has finished: the exit animation has ended, the `` is closed, the scroll lock is released and focus is back on the element that had it before the dialog opened — unless that element is gone or still inert: when stacked surfaces close together, focus can end on the page body. Fires once for every close that finishes, including one you started with `open = false`. Not for a close vetoed in `onClose`, nor for one interrupted by reopening before the animation ends, nor when the dialog is destroyed while open or mid-close (focus is not returned then either). The place to move focus elsewhere, reset a form without a visible flash, or open a follow-up surface. | | open | `boolean` | no | | Controls whether the dialog is visible. Supports bind:open. | | placement | `DialogVariants['placement']` | no | 'center' | Vertical placement within the viewport. Use 'top' for command-palette style positioning. | | preset | `string` | no | | Apply a named preset registered via ``. Prefer this over `class` overrides when the requested look falls outside the semantic intent palette — presets keep hover/active/dark-mode logic coherent and make the custom look reusable across the project. | | size | `DialogVariants['size']` | no | 'sm' | Controls the maximum width of the dialog panel. | | slotClasses | `Partial>` | no | | Per-slot class overrides merged with variant styles. In the same Tailwind bucket `class` wins over the `slotClasses` entry for the element it lands on. Presets and provider defaults sit below both. | | title | `string` | no | | Heading displayed in a header bar. Enables the structured header/body/footer layout. | | transitionDuration | `number` | no | | Override the enter/exit animation duration in milliseconds. Defaults to the overlay token `--blocks-overlay-enter-duration` / `--blocks-overlay-exit-duration` (200ms / 180ms). Set globally via the CSS custom properties or per-instance via this prop. Respects `prefers-reduced-motion`. | | transitionEasing | `(t: number) => number` | no | | Override the enter/exit easing function. Defaults to the overlay token easing (`quintOut`). | | unstyled | `boolean` | no | | Strip all default styles. Combine with slotClasses for fully custom appearance. | Inherited from: - Omit (omit-pattern) ### Types ```ts type DialogSize = NonNullable ``` ```ts type DialogPlacement = NonNullable ``` ```ts type DialogIntent = NonNullable ``` ### Slots (slotClasses keys) `dialog`, `backdrop`, `panel`, `content`, `header`, `titleGroup`, `icon`, `title`, `closeButton`, `body`, `footer`