Toaster
Not yet released
The rewritten Toaster is not yet released. This page documents the upcoming component — APIs and behavior described here may change before release.
Overview
The toaster is the Beacon notification system for AJAX/action outcomes. It has two surfaces:
- Result toasts: success, error, warning, info and loading states for the outcome of an action. Rendered by
EnToaster. - Notices: quiet, momentary feedback pills like "Copied to clipboard", with an optional Undo. Rendered by
EnNotice.
Unlike most components in this library, you don't interact with the Vue components directly. They have no props, slots or events; EnToaster and EnNotice are pure renderers of a shared store, and the entire API lives in the useToaster() composable. Notifications can be fired from anywhere: components, stores, or plain JS modules.
The store is pinned to window, so every bundle on the page (and every non-Vue caller) shares a single toast stack. This is also what powers the legacy window.Toaster adapter.
Setup
For basic use, no setup or imports are needed. The shared instance is bound to the global notifier, so existing patterns keep working as-is:
js
window.Toaster.showSuccess('Your changes have been saved.', 4000);To go beyond the basics (typed results, handles, notices, configuration), import the composable:
js
import { useToaster } from '@front-end/en-components';
const toaster = useToaster();
toaster.success({ title: 'Saved', message: 'Coverage is effective May 1, 2026.' });useToaster() returns the same shared instance on every call, in every bundle. It is the same object bound to window.Toaster, so it's safe to call wherever you need it rather than passing the instance around.
App setup (once per app)
The render components are mounted a single time near the root of the app, alongside the global binding. Within Navigator this is handled for you; only new or standalone apps need to wire it up:
html
<EnToaster />
<EnNotice />js
import { useToaster } from '@front-end/en-components';
window.Toaster = useToaster();Demos on this page
This page mounts <EnToaster /> and <EnNotice /> once at the top, exactly as an app would. In the editable examples below, toaster is the object returned by useToaster().
Result toasts
The severity methods success, error, warning, info and loading are shorthand for show({ ...options, type }). Success/info/warning auto-dismiss with a hover-pausable countdown; errors and loading persist until dismissed.
Loading → result
Every show() call (and the severity shorthands) returns a handle. Use resolve() to morph a toast in place, for example a loading spinner into a success, preserving its position in the stack so it doesn't jump.
Actions and details
Toasts can carry action buttons and a collapsible drawer for raw server detail. When details is present, a Copy error action is added automatically.
Notices
For quiet confirmations that don't need a title or a close button, use notice(). copied(thing) is a shorthand for the common clipboard flow, and passing an undo callback adds an Undo button.
API reference
show(options) → ToastHandle
Shows a result toast. Honors the visible-stack cap (maxVisible, default 4); excess toasts queue and appear as slots free up. The severity shorthand methods take the same options object:
js
toaster.show({ type: 'success', title: 'Saved' });
toaster.success({ title: 'Saved' }); // equivalentToastOptions
| Option | Type | Default | Description |
|---|---|---|---|
type | 'success' | 'error' | 'warning' | 'info' | 'loading' | 'info' | Severity. 'spinner' is accepted as an alias of 'loading'. |
title | string | Bold heading line. | |
message | string | Convenience single body line; appended to lines. | |
lines | Array<string | { text } | { html }> | Body line items. Strings/text render escaped (XSS-safe); { html } items are opt-in and must be pre-sanitized by the caller. | |
html | boolean | false | Treat message as pre-sanitized HTML. |
details | string | Raw server payload shown in a collapsible drawer. Auto-adds a Copy error action. | |
actions | ToastAction[] | Action buttons (see below). | |
icon | string | per type | Override the default severity icon (icomoon class). |
duration | number | per type | Auto-dismiss in ms; 0 persists. Defaults: success 5000, info 6000, warning 8000, error 0, loading 0. |
dismissible | boolean | true | Show the close button. |
ToastAction
| Option | Type | Default | Description |
|---|---|---|---|
label | string | Button text. | |
onClick | function | Click handler; receives the toast object. | |
variant | 'primary' | 'ghost' | 'primary' | Button tone (ghost renders btn-secondary). |
icon | string | Leading icomoon class, e.g. 'icon-redo'. | |
close | boolean | true | Dismiss the toast after the action runs. |
ToastHandle
| Member | Description |
|---|---|
id | The toast's id. |
update({ title?, message? }) | Patch the live toast's title/message. |
resolve(type, options?) | Morph the toast in place (e.g. loading → success), keeping its id and stack position. Returns the handle. |
dismiss() | Dismiss the toast. |
notice(text, options?) → NoticeHandle
Shows a lightweight feedback pill. No title, no close button, auto-dismisses.
| Option | Type | Default | Description |
|---|---|---|---|
icon | string | 'icon-check-circle-solid' | Leading icomoon class. |
undo | function | When provided, an Undo button is shown that calls this and dismisses. | |
duration | number | 2200 | Auto-dismiss in ms. |
The handle exposes a single dismiss() method.
copied(thing, options?) → NoticeHandle
Shorthand for clipboard flows. Shows "<thing> copied to clipboard" with the copy icon.
setDefaults(patch) / configure(patch)
Merges app-level defaults. durations is deep-merged; all other keys are replaced.
| Key | Type | Default | Description |
|---|---|---|---|
placement | 'top-center' | 'top-right' | 'bottom-right' | 'top-left' | 'top-center' | Toast region position. |
accent | 'medallion' | 'rail' | 'plain' | 'medallion' | Severity accent style. |
density | 'comfortable' | 'compact' | 'comfortable' | Toast sizing. |
progress | boolean | true | Show the countdown bar on auto-dismissing toasts. |
maxVisible | number | 4 | Visible-stack cap before toasts queue. |
loadingDelay | number | 150 | Ms a legacy showSpinner() waits before appearing; if the action resolves/hides first, no spinner shows. 0 shows immediately. (Does not affect the modern loading() API.) |
loadingMinVisible | number | 500 | Once a showSpinner() is shown, the min ms it stays before it can morph — so it can't flash on and off. |
durations | object | see above | Per-type auto-dismiss ms (0 persists). |
noticePlacement | 'bottom-center' | 'bottom-right' | 'bottom-center' | Notice region position. |
noticeTheme | 'light' | 'dark' | 'light' | Notice pill theme. |
noticeDuration | number | 2200 | Notice auto-dismiss ms. |
Other methods
| Method | Description |
|---|---|
dismissAll() | Clear everything immediately: visible toasts, the queue, and all notices. |
dismissToast(id) / dismissNotice(id) | Dismiss a single toast/notice by id (the handles wrap these). |
copyText(text) | Copy text to the clipboard (async API with a synchronous fallback; best-effort). |
promise(p, { loading?, success?, error? }) | Drive a spinner → result from a promise: shows the (deferred) spinner, then morphs it to a success or error when p settles. success/error may be strings or functions of the resolved value / rejection. Resolves or rejects through to the caller. Because the spinner is deferred, fast work shows only the result with no spinner flash. |
Legacy window.Toaster
The object returned by useToaster() is also a drop-in replacement for the legacy global notifier. It is bound once at app startup, and the existing call sites keep working unchanged:
js
import { useToaster } from '@front-end/en-components';
window.Toaster = useToaster();The legacy surface is single-message: each show* call replaces the current toast, except spinner → result, which morphs in place. Auto-hide applies only when an explicit ms is passed; errors and the spinner always persist.
To avoid flicker on fast actions, showSpinner() is deferred by loadingDelay ms (default 150) — if the work finishes first, no spinner ever appears — and once shown it stays at least loadingMinVisible ms (default 500) before morphing. So most quick saves show only the result, and a spinner that does appear can't blink in and out. The modern loading() API is unaffected and shows immediately. Both timings are configurable via setDefaults (set loadingDelay: 0 to disable the deferral).
| Legacy method | Behavior | Modern equivalent |
|---|---|---|
showError(message) | Replaces the current toast with a persistent error. | toaster.error({ message }) |
showSuccess(message, ms?) | Success toast; with ms it auto-hides and the returned Promise resolves on dismiss. | toaster.success({ message, duration }) |
showWarning(message, ms?) | Warning toast; same Promise contract as showSuccess. | toaster.warning({ message, duration }) |
showErrorModel(model, hidePropertyNames?) | Renders a validation model's Errors[], one line per entry, as "<ErrorMessage> (<PropertyName>)". The (<PropertyName>) is omitted when an entry has no property name. | toaster.error({ lines }) |
showSuccessModel(model, ms?) | Renders a success model's Messages[], one line each. | toaster.success({ lines, duration }) |
showErrorGeneric() | The fixed generic "An error occurred…" message. | |
showSpinner(altMessage?) | Loading state, deferred by loadingDelay (see note above); persists until hidden or morphed by the next showSuccess/showError. | toaster.loading({ title }) + handle.resolve() |
hideSpinner() / hideError() / hideSuccess() / hideWarning() | Hide the current toast if it matches that type. | handle.dismiss() |
hide() | Clear everything. | toaster.dismissAll() |
addError(message) | Append a line to the current error toast (or start one). |
Related
- Composables: other shared composables (
usePagination). - Confirmation Modal: for outcomes that require a user decision rather than a notification.