Toast
Headless toast queue, provider, region, and parts with typed imperative API.
|
|
| Package |
@vizejs/ui/toast |
| Maturity |
stable |
| Own the source |
vize lib pull toast |
| Requires |
context, id, live-region, presence |
| Aliases |
toast, toaster, snackbar, notification, sonner |
| Covers |
WAI-ARIA live regions, Radix Toast, Sonner, React Aria Toast, Reka UI Toast |
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 { ToastProvider, ToastViewport, Toaster, ToastRoot, Toast, ToastTitle, ToastDescription, ToastAction, ToastClose } from "@vizejs/ui/toast";
Or copy the source into your project with vize lib pull toast (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
<!-- Toast provider with a shared store that queues notifications into the default viewport. -->
<script setup lang="ts">
import { createToastStore, ToastProvider, ToastViewport } from "@vizejs/ui/toast";
const store = createToastStore({ duration: 4000 });
function saveProfile(): void {
store.success({ title: "Profile saved" });
}
function archiveMessage(): void {
store.toast({
title: "Message archived",
description: "You can find it in the Archive folder.",
action: { label: "Undo", altText: "Restore the message from the Archive folder" },
});
}
</script>
<template>
<ToastProvider :store label="Notifications">
<button type="button" @click="saveProfile">Save profile</button>
<button type="button" @click="archiveMessage">Archive message</button>
<ToastViewport />
</ToastProvider>
</template>
API
ToastProvider<Data = unknown>
Source: src/families/feedback/toast/toast-provider.vue
Props
| Prop |
Type |
Default |
Description |
store |
ToastStore<Data> |
undefined |
Externally created store, for example a module-level store shared with code outside components. undefined creates a request-local store. |
duration |
number |
undefined |
Default auto-dismiss duration in milliseconds. undefined keeps the store default (5000). |
limit |
number |
undefined |
Maximum number of visible toasts. undefined keeps the store default (3). |
label |
string |
"Notifications" |
Accessible name of the notification region, suffixed with the hotkey. |
hotkey |
readonly string[] |
["F8"] |
Keys that move focus to the region. Modifier tokens are altKey, ctrlKey, metaKey, and shiftKey; other tokens match code or key. |
swipeDirection |
ToastSwipeDirection |
"right" |
Direction a toast must be swiped to dismiss it. |
swipeThreshold |
number |
50 |
Pixels a swipe must travel before release dismisses the toast. |
pauseOnPageHidden |
boolean |
true |
Pause timers while document.visibilityState is hidden. |
Slots
| Slot |
Slot props |
Description |
default |
{ readonly store: ToastStore<Data> } |
Application subtree, usually including a ToastViewport. |
Exposed
| Member |
Type |
Description |
store |
ToastStore<Data> |
Store owned or forwarded by the provider. |
ToastViewport<Data = unknown>
Source: src/families/feedback/toast/toast-viewport.vue
Props
| Prop |
Type |
Default |
Description |
pauseOnHover |
boolean |
true |
Pause every timer while a pointer hovers the region. |
pauseOnFocus |
boolean |
true |
Pause every timer while focus is inside the region. |
announce |
boolean |
true |
Announce new and updated toasts through the embedded live region. |
Slots
| Slot |
Slot props |
Description |
default |
ToastViewportSlotState<Data> |
Renders one visible toast. Falls back to ToastRoot with every part. |
Exposed
| Member |
Type |
Description |
element |
HTMLElement | null |
Rendered region element. |
focus |
(options?: FocusOptions) => void |
Move focus to the region, as the hotkey does. |
Toaster<Data = unknown>
Source: src/families/feedback/toast/toast-viewport.vue
Props
| Prop |
Type |
Default |
Description |
pauseOnHover |
boolean |
true |
Pause every timer while a pointer hovers the region. |
pauseOnFocus |
boolean |
true |
Pause every timer while focus is inside the region. |
announce |
boolean |
true |
Announce new and updated toasts through the embedded live region. |
Slots
| Slot |
Slot props |
Description |
default |
ToastViewportSlotState<Data> |
Renders one visible toast. Falls back to ToastRoot with every part. |
Exposed
| Member |
Type |
Description |
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
focus |
— |
|
ToastRoot<Data = unknown>
Source: src/families/feedback/toast/toast-root.vue
Props
| Prop |
Type |
Default |
Description |
toast (required) |
ToastRecord<Data> |
required |
Toast snapshot to render, usually from the ToastViewport slot. |
Slots
| Slot |
Slot props |
Description |
default |
ToastSlotState<Data> |
Toast parts. Receives the toast snapshot, open state, and swipe phase. |
Exposed
| Member |
Type |
Description |
element |
HTMLLIElement | null |
Rendered list item. |
dismiss |
(reason?: ToastDismissReason) => boolean |
Close this toast. |
Toast<Data = unknown>
Source: src/families/feedback/toast/toast-root.vue
Props
| Prop |
Type |
Default |
Description |
toast (required) |
ToastRecord<Data> |
required |
Toast snapshot to render, usually from the ToastViewport slot. |
Slots
| Slot |
Slot props |
Description |
default |
ToastSlotState<Data> |
Toast parts. Receives the toast snapshot, open state, and swipe phase. |
Exposed
| Member |
Type |
Description |
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
dismiss |
— |
|
ToastTitle
Source: src/families/feedback/toast/toast-title.vue
Slots
| Slot |
Slot props |
Description |
default |
— |
Title contents. Falls back to the toast title. |
Exposed
| Member |
Type |
Description |
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
ToastDescription
Source: src/families/feedback/toast/toast-description.vue
Slots
| Slot |
Slot props |
Description |
default |
— |
Description contents. Falls back to the toast description. |
Exposed
| Member |
Type |
Description |
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
ToastAction
Source: src/families/feedback/toast/toast-action.vue
Props
| Prop |
Type |
Default |
Description |
altText (required) |
string |
required |
Required alternative that tells screen-reader users how to perform the action without the toast, which may close before they reach it. |
Events
| Event |
Payload |
Description |
click |
[nativeEvent: MouseEvent] |
Fired before the toast action runs. Call preventDefault() to keep the toast open. |
Slots
| Slot |
Slot props |
Description |
default |
— |
Action label. Falls back to the toast action label. |
Exposed
| Member |
Type |
Description |
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
focus |
— |
|
ToastClose
Source: src/families/feedback/toast/toast-close.vue
Props
| Prop |
Type |
Default |
Description |
ariaLabel |
string |
"Dismiss notification" |
Accessible name of the close button. |
Events
| Event |
Payload |
Description |
click |
[nativeEvent: MouseEvent] |
Fired before closing. Call preventDefault() to keep the toast open. |
Slots
| Slot |
Slot props |
Description |
default |
— |
Close button contents. |
Exposed
| Member |
Type |
Description |
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
focus |
— |
|
Behavior
Normative state x input -> outcome table for @vizejs/ui/toast: the pure
createToastStore queue, useToast, toast-provider.vue, toast-viewport.vue
(Toaster), toast-root.vue, toast-title.vue, toast-description.vue,
toast-action.vue, and toast-close.vue. Every row names the test that proves it.
| Area |
State x input |
Observable outcome |
Proven by |
| SSR-safe store |
store created, never started, toasts added |
ids are deterministic (toast-1, ...); no timer runs, so server rendering never schedules work |
toast-store.test.ts › store is inert until started and generates deterministic ids |
| Auto dismiss |
started store, visible toast, duration elapses |
toast closes with reason timeout; onAutoClose then onDismiss fire once; remove drops it |
toast-store.test.ts › started timers auto-dismiss visible toasts ... |
| Limit and queue |
more open toasts than limit |
extra toasts wait in queuedToasts ordered high > normal > low, then creation order; a closed slot promotes the next |
toast-store.test.ts › limit queues extra toasts and high priority jumps ... |
| Queued timers |
toast waiting in the queue |
its timer does not run until shown; dismissing a queued toast removes it immediately |
toast-store.test.ts › queued toasts keep their full duration ... |
| Pause/resume |
overlapping pause reasons, then resume |
timers stop while any reason is active and resume with the remaining time; stop freezes every timer |
toast-store.test.ts › pause reasons overlap and resume keeps the remaining time |
| Replace/update |
toast({ id }) for an existing id, or update(id, patch) |
toast is replaced in place, revision increments, timer restarts; loading defaults to Infinity; unknown id returns false |
toast-store.test.ts › an explicit id replaces the existing toast ... |
| Promise toast |
promise(p, { loading, success, error }) |
loading toast becomes success (value-derived) or error (reason-derived) in place; the original promise is returned |
toast-store.test.ts › promise toasts move from loading ...; toast.test.ts › promise toasts render loading ... |
| Dismiss all |
dismiss() without id |
every open toast closes once; a second call reports false; clear empties the store |
toast-store.test.ts › dismiss without an id closes every toast ... |
| Validation |
invalid limit, duration, or blank action altText |
throws VIZE_UI_TOAST_OPTION |
toast-store.test.ts › configure and options validate their inputs |
| Hotkey helpers |
hotkey tokens and keyboard events |
labels read Alt+T; modifiers match event flags and other tokens match code or key |
toast-store.test.ts › hotkey helpers format labels ... |
| Region |
ToastViewport renders visible toasts |
<section aria-label="Notifications (F8)" tabindex="-1"> wraps an <ol> of <li role="status" aria-live="off"> items |
toast.test.ts › renders a labelled region with list items and every default part |
| Exit |
toast closes without CSS exit motion |
presence completes immediately and the store removes the toast; with motion it waits for animationend/transitionend |
toast.test.ts › visible toasts auto-dismiss after their duration ... |
| Pause sources |
pointer over region, focus within region, visibilityState hidden |
every timer pauses (data-paused="true") and resumes with remaining time afterwards |
toast.test.ts › hovering or focusing the region and a hidden page pause timers |
| Hotkey |
document keydown matching hotkey (default F8) |
focus moves to the region and the event is prevented; the region name includes the formatted hotkey |
toast.test.ts › the hotkey moves focus to the region ... |
| Keyboard dismiss |
Escape on a focused dismissible toast, or close button click |
toast dismisses and focus returns to the region; non-dismissible toasts ignore Escape and render no default close button |
toast.test.ts › Escape and the close button dismiss ... |
| Swipe |
pointer drag along swipeDirection |
data-swipe moves start -> move -> end/cancel, --vize-toast-swipe-move-* publishes offset; past threshold dismisses |
toast.test.ts › swiping past the threshold ...; vertical swipe directions publish the y offset |
| Action |
action button activation |
action.onClick runs; unless preventDefault() was called the toast dismisses with reason action |
toast.test.ts › action activation runs the toast callback ... |
| Stacking |
limit smaller than open toasts |
only limit items render; dismissal promotes the highest-priority queued toast |
toast.test.ts › limit stacks visible toasts and promotes queued ones by priority |
| Announcements |
new or updated toasts |
embedded live region speaks title. description. altText, polite by default and assertive for error or high priority |
toast.test.ts › new toasts are announced politely ... |
| Custom render |
viewport default slot |
slot receives typed toast, index, count, and dismiss; parts fall back to toast text |
toast.test.ts › custom slot rendering receives typed data ...; ToastAction requires alt text ... |
| Provider guard |
useToast or parts outside ToastProvider/ToastRoot |
throws VIZE_UI_CONTEXT_MISSING |
toast.test.ts › useToast and parts require a provider |
| SSR |
isolated server requests with toasts created during setup |
byte-identical markup; hydration reuses every item with no warnings; announcements happen only after mount |
toast-ssr.test.ts |
| Types |
typed store, promise phases, options |
Data flows to records and slots; promise success receives the resolved type; closed unions reject unknown values |
toast.types.test-d.ts |
| DOM/SSR/Vapor |
authored SFCs compile |
every SFC compiles in the dom, ssr, and vapor renderer lanes |
scripts/check-renderers.ts |
Public Provider Props
| Prop |
Type |
Default |
Contract |
store |
ToastStore<Data> |
undefined |
External store; otherwise a request-local store is created. |
duration |
number |
undefined |
Default duration in ms; undefined keeps the store default (5000). |
limit |
number |
undefined |
Visible limit; undefined keeps the store default (3). |
label |
string |
"Notifications" |
Region name prefix. |
hotkey |
readonly string[] |
["F8"] |
Keys that focus the region. |
swipeDirection |
"down" | "left" | "right" | "up" |
"right" |
Dismiss swipe direction. |
swipeThreshold |
number |
50 |
Pixels a swipe must travel to dismiss. |
pauseOnPageHidden |
boolean |
true |
Pause timers while the document is hidden. |
Public Viewport Props
| Prop |
Type |
Default |
Contract |
pauseOnHover |
boolean |
true |
Pause timers while a pointer is over the region. |
pauseOnFocus |
boolean |
true |
Pause timers while focus is within the region. |
announce |
boolean |
true |
Speak new and updated toasts via live region. |
Parts And Data
| Target |
Public contract |
| Provider |
data-vize-ui="toast-provider", part="provider" |
| Viewport |
data-vize-ui="toast-viewport", part="viewport", data-paused; list data-vize-ui="toast-list"; announcer data-vize-ui="toast-announcer" |
| Toast |
data-vize-ui="toast", part="root", data-state, data-type, data-priority, data-presence, data-swipe, data-swipe-direction |
| Swipe vars |
--vize-toast-swipe-move-x, --vize-toast-swipe-move-y while dragging; --vize-toast-swipe-end-x, --vize-toast-swipe-end-y on dismiss |
| Title/desc |
data-vize-ui="toast-title" / toast-description, deterministic ids |
| Action |
native button, data-vize-ui="toast-action", data-alt-text |
| Close |
native button, data-vize-ui="toast-close", aria-label default "Dismiss notification" |
Toast ships no stylesheet; the announcer carries inline visually-hidden styles only.