Confirm
Promise-based confirmation helper rendered through the AlertDialog primitive.
| Package | @vizejs/ui/confirm |
| Maturity | stable |
| Own the source | vize lib pull confirm |
| Requires | alert-dialog, context, dialog, id, portal |
| Aliases | useConfirm, confirm dialog, promise dialog, window.confirm replacement |
| Covers | window.confirm, WAI-ARIA alertdialog pattern, Radix Alert Dialog, Mantine modals.openConfirmModal |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { ConfirmProvider } from "@vizejs/ui/confirm";
Or copy the source into your project with vize lib pull confirm (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Awaits a destructive confirmation through the provider's promise-based confirm API. -->
<script setup lang="ts">
import { ref, useTemplateRef } from "vue";
import { ConfirmProvider, type ConfirmProviderExpose } from "@vizejs/ui/confirm";
const confirmRef = useTemplateRef<ConfirmProviderExpose>("confirm");
const files = ref(["invoice-march.pdf", "invoice-april.pdf"]);
async function deleteAll(): Promise<void> {
const provider = confirmRef.value;
if (provider === null) return;
const accepted = await provider.confirm({
title: "Delete all invoices?",
description: "This permanently removes every invoice in this folder.",
confirmLabel: "Delete invoices",
destructive: true,
});
if (accepted) files.value = [];
}
</script>
<template>
<ConfirmProvider ref="confirm">
<ul>
<li v-for="file in files" :key="file">{{ file }}</li>
</ul>
<button type="button" :disabled="files.length === 0" @click="deleteAll">Delete all</button>
</ConfirmProvider>
</template>
API
ConfirmProvider
Source: src/families/overlays/confirm/confirm-provider.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string | null |
undefined |
Consumer-owned base id of the rendered alert dialog. null and undefined use a deterministic fallback. |
confirmLabel |
string |
"Confirm" |
Default label of the accepting action for confirm() requests. |
cancelLabel |
string |
"Cancel" |
Default label of the cancelling action. |
to |
string | HTMLElement |
"body" |
CSS selector or element the alert dialog layer is moved into. |
portalDisabled |
boolean |
false |
Render the alert dialog in place instead of teleporting it. |
lockScroll |
boolean |
true |
Lock document scroll while a request is on screen. |
Events
| Event | Payload | Description |
|---|---|---|
settle |
[request: ConfirmRequest, value: string | null] |
Fired after a request settles with its chosen action value, or null when cancelled. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
— | Application subtree that may call useConfirm(). |
content |
ConfirmSlotProps |
Replace the alert dialog body for the active request. |
Exposed
| Member | Type | Description |
|---|---|---|
pending |
number |
Number of queued requests, including the one on screen. |
active |
ConfirmRequest | null |
Request currently on screen, or null. |
state |
ConfirmState |
Stable state token. |
cancelAll |
— | |
choose |
— | |
confirm |
— |
Behavior
Normative state x input -> outcome table for @vizejs/ui/confirm (confirm-provider.vue plus
useConfirm() / createConfirmQueue() in confirm-runtime.ts). The provider renders the
existing AlertDialog primitive (alert-dialog-content.vue inside the Dialog root, portal,
overlay, title, description, and close parts) for the request at the head of a FIFO queue.
Every row names the test that proves it (confirm.test.ts, confirm-ssr.test.ts, or
confirm.types.test-d.ts).
| Surface | Contract |
|---|---|
| API | useConfirm<Data>() returns confirm(options): Promise<boolean>, choose(options): Promise<Value | null>, pending, and cancelAll(). |
| Queue | Requests are shown one at a time in FIFO order; each settles exactly once. |
| Dialog | The active request renders role="alertdialog", modal, title-labelled, focus-contained, with outside presses ignored. |
| Exit | With optional component-dialog.css, a settled request remains as an inert, hidden-from-AT visual layer until its animation ends; the next request opens immediately. |
| Data | data-vize-ui="confirm-provider", data-state (idle/pending), data-pending, data-confirm-kind, data-confirm-action, data-destructive. |
| SSR | The queue touches no DOM and starts no timers; server output is deterministic and hydrates without diagnostics. |
| State x input | Outcome | Proven by |
|---|---|---|
idle x confirm() |
Opens a labelled, described alertdialog, focuses the cancel action first, marks destructive actions. | confirm() opens a labelled alertdialog and resolves true from the accepting action |
| pending x accepting action | Resolves true, emits settle, closes, and returns focus to the previously focused element. |
confirm() opens a labelled alertdialog and resolves true from the accepting action |
| pending x cancel action or Escape | Resolves false; provider labels apply; requests without a description reference no description. |
cancel and Escape resolve false, and missing descriptions omit aria-describedby |
pending x further requests; cancelAll() |
Later requests wait in FIFO order and pending counts them; cancelAll() settles every request false. |
requests queue in FIFO order and cancelAll settles every pending request |
| pending x styled exit; next request | Resolves the settled promise and opens the next request immediately, retaining only an inert visual layer until exit completes. | styled exits keep settled requests inert while the next request opens immediately |
| pending x zero-duration or reduced motion | Removes the closed visual layer without delaying focus restoration or the next request. | zero-duration and reduced-motion exits remove settled requests immediately |
| closing x rapid new request | Cancels stale focus restoration; the old exit event cannot settle or steal focus from the new request. | reopening during a styled exit cannot steal focus or settle the new request |
idle x choose() |
Renders one button per action; resolves the typed chosen value, or null on cancel. |
choose() resolves the typed action value or null |
| empty title, duplicate or empty action values | Rejects with VIZE_UI_CONFIRM_OPTION without queueing. |
invalid options throw stable diagnostics |
content slot |
Replaces the body; resolve(value) settles with a known action value, cancel() settles cancelled, unknown values are ignored; data is forwarded. |
the content slot replaces the body and settles through resolve and cancel |
| provider unmount | Pending requests resolve as not confirmed, and later requests resolve immediately. | unmounting the provider resolves pending and later requests as not confirmed |
| default portal | The alert dialog teleports to body after mount and still settles requests. |
the provider teleports the dialog to the body by default |
useConfirm() without provider |
Throws VIZE_UI_CONFIRM_PROVIDER_MISSING. |
useConfirm outside a provider throws a stable diagnostic |
| server render | Idle output is byte-identical with no dialog layer. | renders byte-identical idle markup with no dialog layer |
| server render with a request made during child setup | Markup stays idle and deterministic; idle markup hydrates with zero diagnostics. | requests made while rendering on the server never change markup; idle markup hydrates |
| public types | choose infers the literal action union, data follows the Data argument, and invalid options fail. |
src/families/overlays/confirm/confirm.types.test-d.ts |