Alert Dialog
A dialog that requires a user response to proceed. It does not close on backdrop click. The trigger and close match Button. A cta close uses the stronger wash step. The popup has no stroke. The title and description are Light.
Anatomy
<UiAlertDialogRoot>
<UiAlertDialogTrigger>Open</UiAlertDialogTrigger>
<UiAlertDialogPortal>
<UiAlertDialogBackdrop />
<UiAlertDialogViewport>
<UiAlertDialogPopup>
<UiAlertDialogTitle>Title</UiAlertDialogTitle>
<UiAlertDialogDescription>Body</UiAlertDialogDescription>
<UiAlertDialogClose>Cancel</UiAlertDialogClose>
</UiAlertDialogPopup>
</UiAlertDialogViewport>
</UiAlertDialogPortal>
</UiAlertDialogRoot>
Examples
Open from a menu
Control the dialog and open it from a menu item click. The menu closes first; the alert stays until Cancel, the filled action, or Escape.
Close confirmation
Nest the alert inside a controlled Dialog. If the parent would close while the textarea has text, keep the dialog open and show the alert instead. The parent popup sets data-nested-dialog-open and --nested-dialogs. Nested backdrops are not rendered, so the dialog stays visible behind the alert.
Detached triggers
For a one-off, put UiAlertDialogTrigger inside Root. When that is impractical, create a handle with createAlertDialogHandle() and pass it to both the trigger and the root.
<script setup>
import { createAlertDialogHandle } from '~/lib/ui/alert-dialog'
const demoAlertDialog = createAlertDialogHandle()
</script>
<template>
<UiAlertDialogTrigger :handle="demoAlertDialog">Open</UiAlertDialogTrigger>
<UiAlertDialogRoot :handle="demoAlertDialog">
…
</UiAlertDialogRoot>
</template>
Multiple triggers
One alert can be opened by several triggers. Place multiple triggers inside Root, or give detached triggers the same handle. Pass payload on the trigger and read it from Root’s default slot.
<UiAlertDialogRoot v-slot="{ payload }">
<UiAlertDialogTrigger :payload="{ message: 'left photo' }">Left photo</UiAlertDialogTrigger>
<UiAlertDialogTrigger :payload="{ message: 'right photo' }">Right photo</UiAlertDialogTrigger>
…
</UiAlertDialogRoot>
Controlled mode with multiple triggers
Use v-model:open (or open / @update:open) with a handle. Set id on each trigger and triggerId on Root so the matching trigger receives data-popup-open. Opening from a plain button calls handle.show(payload, id).
API reference
Root
Groups all parts of the alert dialog. Renders nothing of its own. Default slot receives { payload, triggerId }.
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | false | Uncontrolled initial open. Use open / v-model:open for a controlled dialog. |
open | boolean | — | Controlled open state (v-model:open). |
handle | BaseAlertDialogHandle | — | Links detached triggers. Create with createAlertDialogHandle(). |
triggerId | string | null | — | Active trigger id in controlled mode. |
Trigger
Button that opens the alert dialog. Renders a <button>.
| Prop | Type | Default | Description |
|---|---|---|---|
disabled | boolean | — | Ignore presses. Sets data-disabled. |
handle | BaseAlertDialogHandle | — | Detached handle. Required when the trigger is outside Root. |
payload | unknown | — | Value exposed on Root’s slot when this trigger opens the dialog. |
id | string | generated | Trigger id. Used with Root triggerId. |
| Attribute | Description |
|---|---|
data-popup-open | Present when this trigger’s dialog is open. |
data-disabled | Present when the trigger is disabled. |
Portal
Teleports to body while the overlay is present (useCssPresence).
| Attribute | Description |
|---|---|
data-open | Present when the dialog is open. |
data-closed | Present while present but not open (exit transition). |
data-nested | Present when nested in another overlay. |
data-starting-style | Present while animating in. |
data-ending-style | Present while animating out. |
Backdrop
Covers the viewport. Does not close the dialog. Nested dialogs skip rendering the child backdrop unless forceRender is set. Uses position: absolute inside the fixed portal.
| Prop | Type | Default | Description |
|---|---|---|---|
forceRender | boolean | — | Render even when nested. |
| Attribute | Description |
|---|---|
data-open | Present when the dialog is open. |
data-closed | Present when the dialog is closed. |
data-starting-style | Present while animating in. |
data-ending-style | Present while animating out. |
Viewport
Centers the popup.
| Attribute | Description |
|---|---|
data-open | Present when the dialog is open. |
data-closed | Present when the dialog is closed. |
data-nested | Present when nested in another overlay. |
data-nested-dialog-open | Present when a nested dialog is open. |
data-starting-style | Present while animating in. |
data-ending-style | Present while animating out. |
Popup
role="alertdialog". Escape closes. Focus stays inside until close. Enter and leave use data-starting-style / data-ending-style (scale 0.98, 100ms). No animation library. No drop-shadow.
| Attribute | Description |
|---|---|
data-open | Present when the dialog is open. |
data-closed | Present when the dialog is closed. |
data-nested | Present when nested in another overlay. |
data-nested-dialog-open | Present when a nested dialog is open. |
data-starting-style | Present while animating in. |
data-ending-style | Present while animating out. |
| Variable | Description |
|---|---|
--nested-dialogs | How many dialogs are nested inside this one. |
Title
Heading that labels the dialog. Renders an <h2>.
Description
Supporting text. Renders a <p>.
Close
Button that sets open to false. Add class="cta" for the filled action.
| Prop | Type | Default | Description |
|---|---|---|---|
disabled | boolean | — | Ignore presses. Sets data-disabled. |
| Attribute | Description |
|---|---|
data-disabled | Present when the button is disabled. |
createAlertDialogHandle
Creates a handle that connects UiAlertDialogRoot with detached UiAlertDialogTrigger components.
const handle = createAlertDialogHandle<{ message: string }>()
handle.show({ message: 'Delete project?' }, 'alert-trigger-2')
handle.hide()
| Field | Description |
|---|---|
open | Ref of whether the dialog is open. |
payload | Ref of the active trigger payload. |
triggerId | Ref of the active trigger id. |
show(payload?, triggerId?) | Open the dialog. |
hide() | Close the dialog. |