Skip to main content
cngx-src documentation

CngxToastOutlet

ComponentPrimaryOnPushNo encapsulationv0.1.0WCAG AA

projects/ui/feedback/toast/toast-outlet.ts

Import#

import { CngxToastOutlet } from '@cngx/ui/feedback'

Description#

Metadata#

Host#

Dependencies#

CngxToasterinject()service

Relationships

Index#

Inputs#

insertPosition#"start" | "end"
input()

Insert new toasts at start or end of the stack.

default 'start'
maxVisible#number
input()

Maximum visible toasts - oldest are evicted.

default 3
input()

Stack position.

default 'bottom-end'

HostBindings#

BindingExpression
[class]positionClass()

Default visuals for CngxToastOutlet. The host carries .cngx-toast-outlet and is fixed-positioned with z-index: 9999 so toasts overlay dialogs and popovers. Each toast renders as .cngx-toast with __icon, __body, __message, __title, __description, __count, __action, and __dismiss children. Toasts use their own --cngx-toast-* namespace, separate from alert and banner so the three feedback channels can be themed independently.

Placement modifiers

Six anchor classes on the outlet, three vertical x two horizontal (center variants use a transform):

  • --top-start / --top-center / --top-end
  • --bottom-start / --bottom-center / --bottom-end

Variants

Severity classes paint the leading-edge stripe and the icon color:

  • .cngx-toast--info - info accent
  • .cngx-toast--success - success accent
  • .cngx-toast--warning - warning accent
  • .cngx-toast--error - error accent

Slots

  • .cngx-toast__icon - severity glyph (color tracks severity)
  • .cngx-toast__default-icon - SVG fallback when no custom icon is projected
  • .cngx-toast__message - body copy
  • .cngx-toast__title - bold header
  • .cngx-toast__description - secondary copy, line-clamped via --cngx-toast-description-max-lines (default 3)
  • .cngx-toast__count - trailing message-count badge (60% opacity)
  • .cngx-toast__action - underlined inline action button
  • .cngx-toast__dismiss - dismiss control

Toasts enter via 200ms cngx-toast-enter; the animation no-ops under prefers-reduced-motion.

Inheritance

  • --cngx-toast-bg -> --cngx-color-surface
  • --cngx-toast-color -> --cngx-color-text

Dark mode

Three hooks deepen the drop shadow, brighten every severity accent so the leading-edge stripe stays perceptible against the darker toast surface, and lift the description text to the cool muted ramp:

  • prefers-color-scheme: dark
  • [data-color-scheme="dark"]
  • .dark class

Index#

Layout

--cngx-toast-z-index#<number>
Default value 9999

Stacking-context order - high so toasts overlay dialogs / popovers.

--cngx-toast-gap#<length>
Default value 8px

Vertical gap between stacked toasts.

--cngx-toast-outlet-padding#*
Default value 16px

Outer padding around the toast outlet (viewport offset).

--cngx-toast-max-width#<length>
Default value 420px

Maximum inline size of each toast - caps long messages.

--cngx-toast-inner-gap#<length>
Default value 10px

Gap between icon, body, and dismiss button inside a toast.

--cngx-toast-padding#*
Default value 12px 16px

Padding shorthand inside each toast.

--cngx-toast-border-radius#<length>
Default value 8px

Corner radius of each toast.

--cngx-toast-icon-size#<length>
Default value 20px

Default icon size when no custom icon is projected.

--cngx-toast-action-padding#*
Default value 4px 0

Padding shorthand of the inline action button.

Surface

--cngx-toast-bg#<color>
Default value oklch(1 0 0)

Background of each toast.

--cngx-toast-color#<color>
Default value oklch(0.25 0.015 250)

Text color of each toast.

--cngx-toast-shadow#*
Default value 0 4px 12px oklch(0 0 0 / 0.15)

Drop-shadow of each toast.

--cngx-toast-accent-width#<length>
Default value 3px

Width of the leading-edge severity stripe.

Motion

--cngx-toast-enter-duration#<time>
Default value 200ms

Duration of the enter animation.

--cngx-toast-enter-easing#*
Default value ease-out

Easing curve of the enter animation.

Variant / Info

--cngx-toast-info-accent#<color>
Default value oklch(0.62 0.2 250)

Severity stripe of the info variant.

Variant / Success

--cngx-toast-success-accent#<color>
Default value oklch(0.65 0.15 145)

Severity stripe of the success variant.

Variant / Warning

--cngx-toast-warning-accent#<color>
Default value oklch(0.72 0.18 70)

Severity stripe of the warning variant.

Variant / Error

--cngx-toast-error-accent#<color>
Default value oklch(0.62 0.22 25)

Severity stripe of the error variant.

Typography

--cngx-toast-font-size#*
Default value 0.875rem

Font-size of the toast body text.

--cngx-toast-line-height#*
Default value 1.5

Line-height of the toast body text.

--cngx-toast-title-font-weight#<number>
Default value 600

Font-weight of the title slot.

--cngx-toast-title-font-size#*
Default value 0.875rem

Font-size of the title slot.

--cngx-toast-title-color#*
Default value currentColor

Color of the title slot.

--cngx-toast-description-max-lines#<integer>
Default value 3

Maximum number of lines for the description slot before truncation kicks in.

--cngx-toast-description-font-size#*
Default value 0.8125rem

Font-size of the description slot.

--cngx-toast-description-color#<color>
Default value oklch(0.5 0.01 250)

Text color of the description slot.

--cngx-toast-description-line-height#*
Default value 1.4

Line-height of the description slot.

--cngx-toast-action-weight#<number>
Default value 600

Font-weight of the inline action button.

--cngx-toast-action-size#*
Default value 0.8125rem

Font-size of the inline action button.

State / Overflow

--cngx-toast-count-opacity#<number>
Default value 0.6

Opacity of the trailing message-count badge.

Async state bridges

import { ChangeDetectionStrategy, Component } from '@angular/core';

import { createManualState } from '@cngx/common/data';
import { CngxBannerOn, CngxBannerOutlet, CngxToastOn, CngxToastOutlet } from '@cngx/ui/feedback';

// Re-export triggers compodocx file-walker so app.config.ts lands in the
// StackBlitz manifest as src/app/app.config.ts, overriding the hardcoded
// stub — the only way to inject EnvironmentProviders into the playground.
export { appConfig } from './app.config';

/**
 * Async-state bridges — toast + banner without service plumbing.
 *
 * One `createManualState<string>()` slot drives two declarative bridges
 * (`cngxToastOn`, `cngxBannerOn`) attached to the same host element.
 * The bridges read the state via input binding (`[cngxToastOn]="saveState"`)
 * and react to status transitions: `loading → success` fires a success
 * toast; `loading → error` fires an error toast AND opens a banner. No
 * subscriptions, no `inject(CngxToaster)`, no `show()` calls.
 *
 * Same pattern composes with any `CngxAsyncState` producer — `injectAsyncState`,
 * `fromResource`, `fromHttpResource`, the manual state shown here, or a
 * commit-action's exposed `commitState` (see Example 3 / 6).
 */
@Component({
  selector: 'app-root',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [CngxToastOn, CngxBannerOn, CngxToastOutlet, CngxBannerOutlet],
  template: `
    <p style="margin: 0 0 12px; opacity: 0.8; font-size: 0.875rem">
      One <code>createManualState</code> slot drives both bridges on the
      same element. Click a button to push the state through
      <code>loading → success</code> or <code>loading → error</code> and
      watch the toast / banner appear without any explicit
      <code>show()</code> call.
    </p>
    <div
      [cngxToastOn]="saveState"
      [toastSuccess]="'Saved'"
      [toastError]="'Save failed'"
      [cngxBannerOn]="saveState"
      bannerId="save:error"
      [bannerError]="'Save failed — check your connection.'"
      style="display: flex; gap: 8px; flex-direction: column; align-items: flex-start"
    >
      <div style="display: flex; gap: 8px">
        <button type="button" (click)="simulateSuccess()">
          Simulate success
        </button>
        <button type="button" (click)="simulateError()">
          Simulate error
        </button>
      </div>
      <p>Status: {{ saveState.status() }}</p>
    </div>

    <cngx-toast-outlet />
    <cngx-banner-outlet />
  `,
})
export class BridgesExample {
  protected readonly saveState = createManualState<string>();

  protected simulateSuccess(): void {
    this.saveState.set('loading');
    setTimeout(() => this.saveState.setSuccess('Saved!'), 1200);
  }

  protected simulateError(): void {
    this.saveState.set('loading');
    setTimeout(() => this.saveState.setError('Server error'), 1200);
  }
}
export { BridgesExample as AppComponent };