# Toast

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

Source: https://ngwr.dev/reference/components/toast  
Kind: Service, CDK Overlay

## Installation

```angular-ts
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.

```angular-ts
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.

```angular-ts
this.toast.show({
  type: 'success',
  title: 'Saved',
  message: 'Profile updated.',
});
```

```html
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.

```angular-ts
this.toast.show({
  message: 'Permalink copied to clipboard',
  position: 'bottom',
  showCopy: true,
  duration: 6000,
});
```

## Close all

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

## Persistent toast

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

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

## 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()`.

## Position

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

```angular-ts
this.toast.setPosition('bottom-end');
```

## 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.

```typescript
// 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

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `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`.

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `type` | Visual variant. | `'info' \| 'success' \| 'warning' \| 'danger'` | `'info'` |
| `title` | Optional heading. | `string` | `—` |
| `message`required | Body text. | `string` | — |
| `duration` | Auto-dismiss after N ms. 0 disables. Falls back to global config. | `number` | `config.duration` |
| `dismissible` | Show close (×) button. | `boolean` | `true` |
| `position` | Override the corner for this toast only. | `WrToastPosition` | `config.position` |
| `showProgress` | Override the progress bar visibility. | `boolean` | `config.showProgress` |
| `showCopy` | Override the copy button visibility. | `boolean` | `config.showCopy` |

## WrToastConfig

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

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `position` | Default corner the stack renders in. | `WrToastPosition` | `'top-end'` |
| `duration` | Default auto-dismiss in ms. 0 disables. | `number` | `4000` |
| `showProgress` | Render a countdown bar; pauses on hover. | `boolean` | `true` |
| `showCopy` | Render a copy-message button on each toast. | `boolean` | `false` |
| `showCloseAll` | Render a "Close all" button above the stack. | `boolean` | `true` |
| `closeAllThreshold` | Minimum stack size before "Close all" appears. | `number` | `2` |
| `maxStack` | Max visible toasts; oldest dismissed when exceeded. 0 = unlimited. | `number` | `5` |
| `labels` | Strings 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.

| Variable | Default | Declared on |
| --- | --- | --- |
| `--wr-toast-accent` | `var(--wr-color-primary)` | `.wr-toast` +1 variant override |
| `--wr-toast-bg` | `var(--wr-color-surface)` | `.wr-toast` |
| `--wr-toast-border` | `var(--wr-color-outline)` | `.wr-toast` |
| `--wr-toast-i` | `var(--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-message` | `var(--wr-color-on-surface-muted)` | `.wr-toast` |
| `--wr-toast-title` | `var(--wr-color-on-surface)` | `.wr-toast` |
