ServiceCDK Overlay

Toast

Stack of dismissible notifications anchored to a viewport corner. Service-driven; rendered in a single shared CDK overlay.

Installation

import { WrToast } from 'ngwr/toast';

@Component({...})
export class MyComponent {
  private readonly toast = inject(WrToast);
}

Global config

Register provideWrToastConfig once at bootstrap to set defaults — position, duration, progress bar, copy button, max stack, label strings (i18n). Any field you omit falls back to the library default; the labels sub-object is merged separately so you can override a single string at a time.

import { bootstrapApplication } from '@angular/platform-browser';
import { provideWrToastConfig } from 'ngwr/toast';

import { AppComponent } from './app/app';

bootstrapApplication(AppComponent, {
  providers: [
    provideWrToastConfig({
      position: 'bottom-end',
      duration: 5000,
      showProgress: true,
      showCopy: true,
      maxStack: 5,
      labels: {
        close: 'Закрыть',
        copy: 'Копировать',
        copied: 'Скопировано',
        closeAll: 'Закрыть все',
      },
    }),
  ],
});

Show a toast

Toggle the demo controls below to preview progress bar and copy button on the fired toasts.

this.toast.show({
  type: 'success',
  title: 'Saved',
  message: 'Profile updated.',
});
InfoSuccessWarningDanger
toast.show(...)

Per-toast overrides

Each call to show() accepts the same fields as the global config — handy for one-off positions, copy buttons, longer durations.

this.toast.show({
  message: 'Permalink copied to clipboard',
  position: 'bottom',
  showCopy: true,
  duration: 6000,
});
Show with copy button

Close all

When the stack reaches closeAllThreshold (default 2), a pill-styled “Close all” button appears above the toasts.

Open 3 toastsDismiss all programmatically

Persistent toast

Pass duration: 0 to disable auto-dismiss — the user closes it manually. Progress bar is hidden automatically.

this.toast.show({
  type: 'danger',
  message: 'Network error',
  duration: 0, // no auto-dismiss
});
Open persistent

Layout mode

stack (default, Sonner-style) cascades toasts behind the newest and fans out on hover. list renders them as a classic vertical column. Switch the global default via provideWrToastConfig({ mode: 'list' }) or at runtime via toast.setMode().

Open 3 toasts

Position

Switch the default corner. Per-toast position overrides win for that toast only.

this.toast.setPosition('bottom-end');
Fire here

Toasts, dialogs and the stacking order

A toast raised from inside an open dialog is visible and clickable, and it takes deliberate machinery to keep it that way. There is one toast host overlay for the whole application: it is created with the first toast and disposed when the last one leaves, so its place in the browser's top layer would otherwise be frozen at whenever that first toast appeared — and the top layer is ordered by promotion time, not by z-index. Every dialog and drawer opened afterwards would paint over it, backdrop included.

So the host re-raises itself: on every show(), and again whenever another overlay joins the container. Both directions are covered — a toast fired from a dialog's save handler, and a toast already on screen when a dialog opens. Nothing to configure, and nothing to do from the calling side.

Two edges where it steps aside deliberately. It does not re-raise while focus is inside the toast host, because re-showing a popover is specified to restore focus elsewhere — in practice the two never coincide, since a modal traps focus. And on a platform with no top layer at all (and on the server) there is nothing to raise; the host falls back to ordinary stacking within the overlay container.

Lifetime and scope

WrToast is root-provided and its host is not attached to any component: a toast outlives the component that raised it, survives navigation, and dismisses itself on its own timer. That is deliberate — the point of a toast is to report on work whose screen may already be gone. duration: 0 opts out, and then only a click or dismiss() removes it.

// The six positions, in full — `WrToastPosition` is a union of these and
// nothing else. Both the global config and every `show()` call take one.
type WrToastPosition =
  | 'top-start' | 'top' | 'top-end'
  | 'bottom-start' | 'bottom' | 'bottom-end';

// A toast raised on the way out of a screen still appears, and dismisses
// itself. Keep the handle only when you mean to remove it early.
const ref = this.toast.show({ message: 'Uploading…', duration: 0 });
await this.upload();
ref.dismiss();

// Route-level providers do NOT reach the service — this is ignored:
//   { path: 'admin', providers: [provideWrToastConfig({ position: 'bottom' })] }
// Pass the value per call instead:
this.toast.show({ message: 'Saved', position: 'bottom' });

Because the service is root-provided, so is its configuration: provideWrToastConfig() in a lazy route's providers is ignored — the service reads the root token, and a route-level one is simply never consulted. Nothing warns. Register it once at bootstrap; to vary a value per feature, pass it per call, where every field of the config is also accepted.

Service API

NameDescriptionTypeDefault
show(options)Opens a toast and returns a handle (dismiss()).(WrToastOptions) => WrToastRef
dismiss(id)Removes a single toast by id.(number) => void
dismissAll()Removes every toast in the stack.() => void
setPosition(position)Move the toast stack to a different corner. Affects future toasts.(WrToastPosition) => void

WrToastOptions

Per-call options accepted by toast.show(). Any omitted field falls back to the global WrToastConfig.

NameDescriptionTypeDefault
typeVisual variant.'info' | 'success' | 'warning' | 'danger''info'
titleOptional heading.string
messagerequiredBody text.string
durationAuto-dismiss after N ms. 0 disables. Falls back to global config.numberconfig.duration
dismissibleShow close (×) button.booleantrue
positionOverride the corner for this toast only.WrToastPositionconfig.position
showProgressOverride the progress bar visibility.booleanconfig.showProgress
showCopyOverride the copy button visibility.booleanconfig.showCopy

WrToastConfig

Global configuration registered through provideWrToastConfig. These values back every WrToastOptions field that isn't overridden at call time.

NameDescriptionTypeDefault
positionDefault corner the stack renders in.WrToastPosition'top-end'
durationDefault auto-dismiss in ms. 0 disables.number4000
showProgressRender a countdown bar; pauses on hover.booleantrue
showCopyRender a copy-message button on each toast.booleanfalse
showCloseAllRender a "Close all" button above the stack.booleantrue
closeAllThresholdMinimum stack size before "Close all" appears.number2
maxStackMax visible toasts; oldest dismissed when exceeded. 0 = unlimited.number5
labelsStrings rendered in the UI — override individually for i18n.{ close; copy; copied; closeAll }

CSS variables

Custom properties ngwr/toast publishes. Each default below is declared on the component's own selector, so a :root override is shadowed by it — set them on that selector, on a wrapper you scope yourself, or inline on the element. Unlike the BEM class names, these are the supported way to restyle the component.

VariableDefaultDeclared on
--wr-toast-accentvar(--wr-color-primary).wr-toast +1 variant override
--wr-toast-bgvar(--wr-color-surface).wr-toast
--wr-toast-bordervar(--wr-color-outline).wr-toast
--wr-toast-ivar(--wr-toast-stack-index, 0) only under .wr-toast-host--stack:not(.wr-toast-host--expanded) .wr-toast — unset elsewhere.wr-toast-host--stack:not(.wr-toast-host--expanded) .wr-toast
--wr-toast-messagevar(--wr-color-on-surface-muted).wr-toast
--wr-toast-titlevar(--wr-color-on-surface).wr-toast