Dialog
A flexible overlay for showing messages, forms, or actions. Keeps focus on content while allowing clear, user-friendly interactions.
Destructive confirm
Create / edit form
State-driven actions
Action layout
A single action on a small dialog (xs, sm, md) renders full-width. Everything else sits side-by-side at natural width, right-aligned. Using the #actions slot opts out — you own the layout.
Single-CTA form
Auto-focus a field
Full-canvas (bare)
Master / detail browser
Imperative API
The dialog.* helpers cover the confirm-family surface — confirm and the danger preset — without mounting a <Dialog> yourself.
Pass an actions array to dialog.confirm (or dialog.danger) when a flow needs more than the default confirm + cancel pair. Each action accepts full Button props and its own awaited onClick; the clicked button shows a loading spinner while its handler is pending and every other button is disabled until it settles. Throwing from onClick surfaces inline via the shared error region.
dialog.danger is a one-line preset for irreversible actions. It forces theme: 'red', defaults the icon to a warning triangle, and defaults confirmLabel to 'Delete'. Everything confirm accepts (including actions[]) is forwarded through.
Prompt
dialog.prompt collects structured input through a fields[] array. Each field renders through FormControl, so any FormControl type works — including text, select, checkbox, and combobox. For combobox fields, allowCreate passes the typed query through as the value when nothing in the list matches — handy for category-style fields where users can add new entries inline.
Each field can also declare a validate function. It runs after the built-in required check, in parallel across all fields, and returns a non-empty string to mark the field invalid (shown inline below it) or null for valid. The second argument is a snapshot of every field's current value, so validators can reference siblings. The submit button keeps its loading state while async validators settle.
API Reference
Show types
import type { ButtonProps } from '../Button'
export type DialogSize =
| 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| '2xl'
| '3xl'
| '4xl'
| '5xl'
| '6xl'
| '7xl'
export type DialogTheme = 'yellow' | 'blue' | 'red' | 'green'
export type DialogPosition = 'center' | 'top'
/** Legacy icon appearance — replaced by `theme`. */
export type DialogIconAppearance = 'warning' | 'info' | 'danger' | 'success'
export type DialogIcon = {
name: string
/** Color tone. Replaces deprecated `appearance`. */
theme?: DialogTheme
/** @deprecated Use `theme` instead. */
appearance?: DialogIconAppearance
}
export type DialogActionContext = {
close: () => void
}
export type DialogAction = ButtonProps & {
onClick?: (context: DialogActionContext) => void | Promise<void>
}
/** A `DialogAction` augmented with a reactive `loading` flag, as surfaced to the `#actions` slot. */
export type DialogReactiveAction = DialogAction & { loading: boolean }
/** Legacy blob — accepted for back-compat, warns once. */
export type DialogOptions = {
title?: string
message?: string
size?: DialogSize
icon?: string | DialogIcon
actions?: DialogAction[]
position?: DialogPosition
paddingTop?: string | number
}
export interface DialogProps {
// Visibility — both supported, `open` is canonical.
/** Controls whether the dialog is open (v-model:open). Canonical. */
open?: boolean
/** Controls whether the dialog is open (v-model). Also supported. */
modelValue?: boolean
// Content.
/** Dialog title. Renders the auto-header. */
title?: string
/** Description text rendered below the title. */
message?: string
/** Icon shown next to the title in the auto-header. */
icon?: string | DialogIcon
// Layout.
/** Max-width size of the dialog. Default `'lg'`. */
size?: DialogSize
/** Vertical placement. Default `'center'`. */
position?: DialogPosition
/** Overrides the position-based top padding (escape hatch). */
paddingTop?: string | number
// Actions.
/** Footer action buttons. */
actions?: DialogAction[]
// Behavior.
/** Allow outside-click and Escape to close. Default `true`. */
dismissable?: boolean
/** Show the top-right close button. Default `true`. */
showCloseButton?: boolean
/** Drop the chrome: no padded card, no auto-header, no auto-actions. Default `false`. */
bare?: boolean
// Deprecated.
/** @deprecated Use `dismissable` (inverted) instead. */
disableOutsideClickToClose?: boolean
/** @deprecated Use flat top-level props instead. */
options?: DialogOptions
}
export interface DialogEmits {
/** Fired when the dialog open state changes via `v-model:open`. */
'update:open': [value: boolean]
/** Fired when the dialog open state changes via `v-model`. */
'update:modelValue': [value: boolean]
/** Fired when the dialog transitions to closed. */
close: []
/** Fired after the close animation finishes. */
'after-leave': []
}
/** Scoped payload exposed to every Dialog slot. */
export interface DialogSlotProps {
/** Closes the dialog. */
close: () => void
}
/** Scoped payload for the `#actions` slot. */
export interface DialogActionsSlotProps extends DialogSlotProps {
/** Reactive list of resolved actions (with `loading` state) for re-laying-out auto-rendered buttons. */
actions: DialogReactiveAction[]
}
export interface DialogExposed {
/** Closes the dialog. */
close: () => void
}
export interface DialogSlots {
/** Main content rendered inside the padded card. Exposes `{ close }`. */
default?: (props: DialogSlotProps) => any
/** Title area; accepts arbitrary content (extra buttons next to title, etc.). Exposes `{ close }`. */
title?: (props: DialogSlotProps) => any
/** Footer override; exposes `{ close, actions }`. */
actions?: (props: DialogActionsSlotProps) => any
/** @deprecated Use `#default` + `bare` prop. */
body?: () => any
/** @deprecated Use `#default`. */
'body-main'?: () => any
/** @deprecated Use `#title` for extras (no direct replacement). */
'body-header'?: () => any
/** @deprecated Use `#title`. */
'body-title'?: () => any
/** @deprecated Use `#default`. */
'body-content'?: () => any
}| Prop | Default | Type |
|---|---|---|
open | undefined | boolean Controls whether the dialog is open (v-model:open). Canonical. |
modelValue | undefined | boolean Controls whether the dialog is open (v-model). Also supported. |
title | — | string Dialog title. Renders the auto-header. |
message | — | string Description text rendered below the title. |
icon | — | string | DialogIcon Icon shown next to the title in the auto-header. |
size | undefined | DialogSize Max-width size of the dialog. Default `'lg'`. |
position | undefined | DialogPosition Vertical placement. Default `'center'`. |
paddingTop | — | string | number Overrides the position-based top padding (escape hatch). |
actions | — | DialogAction[] Footer action buttons. |
dismissable | true | boolean Allow outside-click and Escape to close. Default `true`. |
showCloseButton | true | boolean Show the top-right close button. Default `true`. |
bare | false | boolean Drop the chrome: no padded card, no auto-header, no auto-actions. Default `false`. |
disableOutsideClickToClose | undefined | Deprecated — Use `dismissable` (inverted) instead. |
options | — | Deprecated — Use flat top-level props instead. |
| Slot | Payload |
|---|---|
default | DialogSlotProps Main content rendered inside the padded card. Exposes `{ close }`. |
title | DialogSlotProps Title area; accepts arbitrary content (extra buttons next to title, etc.). Exposes `{ close }`. |
actions | DialogActionsSlotProps Footer override; exposes `{ close, actions }`. |
body | Deprecated — Use `#default` + `bare` prop. |
body-main | Deprecated — Use `#default`. |
body-header | Deprecated — Use `#title` for extras (no direct replacement). |
body-title | Deprecated — Use `#title`. |
body-content | Deprecated — Use `#default`. |
| Event | Payload |
|---|---|
update:modelValue | [value: boolean] Fired when the model value changes. |
update:open | [value: boolean] Fired when the open state changes. |
close | [] Fired when the component closes. |
after-leave | [] |