TeqBench Material Banners

@teqbench/tbx-mat-banners
angularmaterialv0.10.0

An opinionated Angular banner component and service with severity-leveled display, an actions group supporting buttons and form controls, and both overlay and inline display modes.

@teqbench/tbx-mat-banners provides persistent, attention-grabbing messages for Angular applications. It fills the gap between small transient notifications and heavier modal dialogs: a wide, horizontally full banner that can carry a short message, a severity indicator, and a small group of action controls, and that stays on screen until the user — or application code — dismisses it.

Two display modes are supported from a single component surface. In overlay mode, TbxMatBannerService creates banners via CDK Overlay on a FIFO queue, one at a time, with optional slide or fade animation and programmatic dismiss. In inline mode, TbxMatBannerComponent is placed directly in a template, controlled by the consumer via bindings, and emits dismiss events.

Severity (default, success, error, warning, information, help) drives both the icon and the color scheme. The six CSS custom-property pairs are aliased from the shared `@teqbench/tbx-mat-severity-theme` tokens, so the five colored tiers stay independent of the active M3 theme palette while the default tier remains theme-responsive. Applications can opt into an inverted palette (white backgrounds with colored text) across every severity-aware @teqbench package by calling provideTbxMatSeverityTheme({ invert: true, applyToRoot: true }) at bootstrap — the flag is app-global and affects notifications and dialogs simultaneously, not banners alone. An optional actions group accepts any mix of buttons, checkboxes, toggles, radio groups, and toggle groups; on dismiss, all collected values are returned alongside the dismiss reason and the action key that triggered it.

The library is designed for Angular 21+ zoneless applications, uses signal inputs, honors prefers-reduced-motion, and exposes a pluggable icon resolver so consumers can use Material Symbols font icons or bundled SVG icons without changing component code.

When to use

Banners are one of three message surfaces in the TeqBench component family. Choose based on the weight of the message and how much interaction it needs.

  • `@teqbench/tbx-mat-notifications` — small, transient messages with at most one action control. Ideally one line of text, two lines acceptable. Use notifications to acknowledge something without interrupting the user's flow.
  • @teqbench/tbx-mat-banners (this package) — wide, persistent messages with multiple action controls. Ideally one line of message text, up to three lines still acceptable. Use a banner when the message needs the user's attention and may offer a few follow-up choices.
  • `@teqbench/tbx-mat-dialogs` — heavier, focused interactions for arbitrary content. Use a dialog when the message is long, the choices are many, or the interaction is complex.

If the content you are putting in a banner is approaching the three-line limit, or if the actions group is growing beyond a handful of controls, that is a signal to escalate to a dialog instead. A banner that behaves like a miniature dialog loses the affordances of both.

At a glance

  • Two display modes — Overlay service for fire-and-forget messages and inline component for template-driven use.
  • Severity-leveled API — Convenience methods for default, success, error, warning, information, and help with matching icons and colors.
  • Actions group — Buttons and form controls (checkbox, toggle, radio group, toggle group) in a single message.
  • FIFO queue — One banner at a time, with signal-based isActive and pendingCount state.
  • Dismiss tracking — Promise resolves with dismiss reason, action key, and collected form control values.
  • Indefinite by default — Banners persist until dismissed; positive duration auto-dismisses, negative is treated as indefinite.
  • Animations — Optional slide or fade on overlay banners; automatically disabled under prefers-reduced-motion.
  • Theming via CSS custom properties — Per-severity colors, gaps, padding, shadow, and z-index exposed as CSS variables.
  • Pluggable icons — Font (Material Symbols) or SVG icon resolver service via DI token.
  • Responsive layout — CSS container queries reflow the actions group onto a second row on narrow viewports.
  • Zoneless ready — Built for Angular 21+ zoneless applications using signal inputs.

Concepts

  • Severity level — A classification (default, success, error, warning, information, help) that selects the icon and color scheme applied to a banner.
  • Actions group — An ordered list of action controls — buttons and form controls — rendered inside the banner and whose values are returned on dismiss.
  • Dismiss reason — The cause of a banner closing — user action, close button, timeout, or one of two programmatic paths (single or all).
  • Queue — A FIFO list of pending banners. One banner is visible at a time in overlay mode; queued banners render in order as each resolves.
  • Provider config — The DI-provided configuration (TBX_MAT_BANNER_PROVIDER_CONFIG) that supplies the severity icon resolver, optional close icon resolver, and default animation.
  • Inline mode — Using TbxMatBannerComponent directly in a consumer template, with visibility and state controlled by the consumer rather than the service.
  • Overlay mode — Using TbxMatBannerService to render a banner in a CDK Overlay above the application, positioned at the top or bottom of the viewport.

Services

TbxMatBannerCloseFontIconService

Default font-based close button icon service

Extends TbxMatFontIconService from @teqbench/tbx-mat-icons and registers the 'close' Material Symbols ligature. Used as the package-provided default for TbxMatBannerProviderConfig.closeIconResolverService when the consumer does not supply a custom close icon resolver.

No default SVG close icon service is provided. Consumers who want SVG close icons must create a concrete subclass of TbxMatSvgIconService from @teqbench/tbx-mat-icons and provide it via TbxMatBannerProviderConfig.closeIconResolverService.

fontSet resolution

The fontSet is resolved by TbxMatFontIconService's fallback chain:

  1. Explicit constructor argumentnew TbxMatBannerCloseFontIconService('material-symbols-sharp')
  2. TBX_MAT_FONT_ICON_DEFAULT_FONT_SET token — set once in app.config.ts
  3. MAT_ICON_DEFAULT_OPTIONS.fontSetAngular Material's global icon default
  4. Error — if none of the above provides a fontSet

Example

Using with MAT_ICON_DEFAULT_OPTIONS:

// app.config.ts — no explicit close icon service needed, package default used
import { MAT_ICON_DEFAULT_OPTIONS } from '@angular/material/icon';
import { TBX_MAT_BANNER_PROVIDER_CONFIG, TbxMatBannerSeverityFontIconService }
    from '@teqbench/tbx-mat-banners';

providers: [
    { provide: MAT_ICON_DEFAULT_OPTIONS, useValue: { fontSet: 'material-symbols-rounded' } },
    {
        provide: TBX_MAT_BANNER_PROVIDER_CONFIG,
        useFactory: () => ({
            severityIconResolverService: new TbxMatBannerSeverityFontIconService(),
            // closeIconResolverService omitted — package default (TbxMatBannerCloseFontIconService) used
        }),
    },
]

TbxMatBannerService

Application-wide banner service for overlay display

Creates full-width banners via Angular CDK Overlay with typed severity levels, configurable duration, and an actions group supporting buttons and form controls.

Banners are queued FIFO and displayed one at a time. When the current banner is dismissed (manually or by timeout), the next queued banner is shown automatically.

All public methods return a TbxMatBannerRef synchronously, containing the consumer's config and a result promise that resolves with a TbxMatBannerResult when the banner is dismissed.

Consumers who do not need the ref or result should use the void prefix to suppress unhandled-promise lint warnings:

void this.bannerService.success('Saved');

Queue state is exposed via Angular signals: - isActive() — whether a banner is currently visible - pendingCount() — number of banners waiting in the queue

When to use

Inject the service and call the convenience methods for each severity level (success(), error(), warning(), information(), help(), default()). Use show() when full control over configuration is needed. Use dismiss() and dismissAll() to programmatically clear banners.

Example

Fire-and-forget:

private readonly banner = inject(TbxMatBannerService);

void this.banner.success('Item saved successfully.');
void this.banner.error('Failed to load data. Please try again.');

Example

Reacting to action dismissal with form values:

const ref = this.banner.warning('Update available', {
    actionsGroup: [
        { type: 'checkbox', key: 'autoUpdate', label: 'Auto-update' },
        { type: 'button', key: 'update', label: 'Update', appearance: 'filled' },
        { type: 'button', key: 'later', label: 'Later' },
    ],
});

const result = await ref.result;
if (result.actionKey === 'update') {
    const autoUpdate = result.actionsGroupValues['autoUpdate'] as boolean;
    this.performUpdate(autoUpdate);
}

TbxMatBannerSeverityFontIconService

Default font-based severity banner icon service

Extends TbxMatSeverityFontIconService from @teqbench/tbx-mat-severity-theme and registers the shared default Material Symbols ligatures (TBX_MAT_SEVERITY_DEFAULT_FONT_LIGATURES) for every severity level. The inherited resolve() and severity methods (default(), success(), error(), etc.) work via the registered mappings.

fontSet resolution

The fontSet is resolved by TbxMatFontIconService's fallback chain:

  1. Explicit constructor argumentnew TbxMatBannerSeverityFontIconService('material-symbols-sharp')
  2. TBX_MAT_FONT_ICON_DEFAULT_FONT_SET token — set once in app.config.ts
  3. MAT_ICON_DEFAULT_OPTIONS.fontSetAngular Material's global icon default
  4. Error — if none of the above provides a fontSet

Example

Using with MAT_ICON_DEFAULT_OPTIONS:

// app.config.ts
import { MAT_ICON_DEFAULT_OPTIONS } from '@angular/material/icon';
import { TBX_MAT_BANNER_PROVIDER_CONFIG, TbxMatBannerSeverityFontIconService }
    from '@teqbench/tbx-mat-banners';

providers: [
    { provide: MAT_ICON_DEFAULT_OPTIONS, useValue: { fontSet: 'material-symbols-rounded' } },
    {
        provide: TBX_MAT_BANNER_PROVIDER_CONFIG,
        useFactory: () => ({
            severityIconResolverService: new TbxMatBannerSeverityFontIconService(),
        }),
    },
]

Example

Using with an explicit fontSet:

// app.config.ts
import { TBX_MAT_BANNER_PROVIDER_CONFIG, TbxMatBannerSeverityFontIconService }
    from '@teqbench/tbx-mat-banners';

providers: [
    {
        provide: TBX_MAT_BANNER_PROVIDER_CONFIG,
        useFactory: () => ({
            severityIconResolverService: new TbxMatBannerSeverityFontIconService('material-symbols-rounded'),
        }),
    },
]

TbxMatBannerSeveritySvgIconService

Default SVG-based severity banner icon service

Extends TbxMatSeveritySvgIconService from @teqbench/tbx-mat-severity-theme and registers the shared default SVG icons (TBX_MAT_SEVERITY_DEFAULT_SVG_ICONS) for every severity level. The inherited resolve() and severity methods (default(), success(), error(), etc.) work via the registered mappings.

Default icons ship with @teqbench/tbx-mat-severity-theme. Subclasses can override any default by overriding initialize() and calling register() with the same key and different SVG markup.

Example

Using the defaults directly:

// app.config.ts
import { TBX_MAT_BANNER_PROVIDER_CONFIG, TbxMatBannerSeveritySvgIconService }
    from '@teqbench/tbx-mat-banners';

providers: [
    {
        provide: TBX_MAT_BANNER_PROVIDER_CONFIG,
        useFactory: () => ({
            severityIconResolverService: new TbxMatBannerSeveritySvgIconService(),
        }),
    },
]

Example

Subclassing with custom SVG markup:

import { Injectable } from '@angular/core';
import { TbxMatBannerSeveritySvgIconService } from '@teqbench/tbx-mat-banners';
import { TbxMatSeverityLevel } from '@teqbench/tbx-mat-severity-theme';

// MyBannerSvgIcons is a consumer-defined subclass
@Injectable()
export class MyBannerSvgIcons extends TbxMatBannerSeveritySvgIconService {
    protected override initialize(): void {
        super.initialize();
        this.register(TbxMatSeverityLevel.Success, '<svg>...</svg>');
    }
}

Components

TbxMatBannerComponent

Banner content component for both inline and overlay display

Renders a severity-styled banner with an optional severity icon, message, actions group (buttons and form controls), and close button.

Display Modes

  • Overlay mode: Created by TbxMatBannerService via CDK Overlay. Receives data through the TBX_MAT_BANNER_DATA injection token. Consumers do not instantiate the component directly in this mode.

  • Inline mode: Placed directly in a consumer's template. Receives data through signal inputs and emits dismiss events via outputs.

Template element order

severity iconmessageactions groupclose button

All elements are optional except the message. The actions group and close button render in the actions slot.

Actions group rendering

Controls render in array order via @switch (control.type). Form control values are tracked internally via writable signals initialized from each control's defaultValue. Current values are collected into the actionsGroupValues record on dismiss.

Example

Overlay mode (consumers do not instantiate directly):

// Consumers use the service:
void this.bannerService.success('Item saved.');

Example

Inline mode:

<tbx-mat-banner [type]="severityLevel" [message]="'Hello'" (dismissed)="onDismiss($event)" />

Interfaces

TbxMatBannerActionButton

Button control in a banner actions group

Defines a clickable button rendered in the banner's actions group slot (between the message and the close button). Clicking the button dismisses the banner. The button's key is included in TbxMatBannerResult.actionKey so the consumer can identify which button triggered the dismissal.

Each button specifies its own appearance and optional icon. The severity panel SCSS provides color token overrides for all six Angular Material button variants, so a 'filled' button inside a success banner automatically receives the success color treatment.

When to use

Add one or more buttons to the actionsGroup array on TbxMatBannerConfig to let users respond inline (e.g., undo, retry, dismiss with intent).

Example

Text button:

{ type: 'button', key: 'undo', label: 'Undo' }

Example

Filled button with icon:

// myIconService is a hypothetical consumer-defined icon resolver
{
    type: 'button',
    key: 'retry',
    label: 'Retry',
    icon: 'refresh',
    appearance: 'filled',
    actionIconResolverService: myIconService,
}

Example

Icon-only button:

// label serves as the aria-label for accessibility
// myIconService is a hypothetical consumer-defined icon resolver
{
    type: 'button',
    key: 'settings',
    label: 'Settings',
    icon: 'settings',
    appearance: 'icon',
    actionIconResolverService: myIconService,
}

TbxMatBannerActionCheckbox

Checkbox control in a banner actions group

Renders a MatCheckbox in the banner's actions group slot. The checkbox value is tracked internally by the banner component and included in TbxMatBannerResult.actionsGroupValues as a boolean under this control's key when the banner is dismissed.

When to use

Add a checkbox to the actionsGroup array on TbxMatBannerConfig to collect a boolean preference alongside the banner's message.

Example

{ type: 'checkbox', key: 'dontShowAgain', label: "Don't show again", defaultValue: false }

TbxMatBannerActionRadioGroup

Radio group control in a banner actions group

Renders a MatRadioGroup with MatRadioButton options in the banner's actions group slot. The selected value is tracked internally by the banner component and included in TbxMatBannerResult.actionsGroupValues as a string under this control's key when the banner is dismissed.

When to use

Add a radio group to the actionsGroup array on TbxMatBannerConfig to collect a single-select choice alongside the banner's message.

Example

{
    type: 'radio-group',
    key: 'priority',
    options: [
        { label: 'Low', value: 'low' },
        { label: 'Medium', value: 'medium' },
        { label: 'High', value: 'high' },
    ],
    defaultValue: 'medium',
}

TbxMatBannerActionToggle

Slide toggle control in a banner actions group

Renders a MatSlideToggle in the banner's actions group slot. The toggle value is tracked internally by the banner component and included in TbxMatBannerResult.actionsGroupValues as a boolean under this control's key when the banner is dismissed.

When to use

Add a toggle to the actionsGroup array on TbxMatBannerConfig to collect a boolean preference alongside the banner's message.

Example

{ type: 'toggle', key: 'autoRetry', label: 'Auto-retry', defaultValue: true }

TbxMatBannerActionToggleGroup

Button toggle group control in a banner actions group

Renders a MatButtonToggleGroup with MatButtonToggle options in the banner's actions group slot. The selected value is tracked internally by the banner component and included in TbxMatBannerResult.actionsGroupValues as a string (single-select) or string[] (multi-select) under this control's key when the banner is dismissed.

When to use

Add a toggle group to the actionsGroup array on TbxMatBannerConfig to collect a selection alongside the banner's message.

Example

Single-select:

{
    type: 'toggle-group',
    key: 'format',
    options: [
        { label: 'JSON', value: 'json' },
        { label: 'CSV', value: 'csv' },
    ],
    defaultValue: 'json',
}

Example

Multi-select with icons:

{
    type: 'toggle-group',
    key: 'channels',
    multiple: true,
    options: [
        { label: 'Email', value: 'email', icon: 'email' },
        { label: 'SMS', value: 'sms', icon: 'sms' },
    ],
    defaultValue: ['email'],
}

TbxMatBannerRef

Reference to a queued or active banner

Returned synchronously from all TbxMatBannerService methods (show(), success(), error(), warning(), information(), help()). Contains two members:

  • config — the consumer-provided configuration, available immediately. - result — a promise that resolves with a TbxMatBannerResult containing the TbxMatBannerDismissReason, the actionKey of the button that triggered dismissal (if applicable), and the actionsGroupValues record when the banner is dismissed.

Fire-and-Forget Usage

Consumers who do not need the dismiss result should prefix the call with void to suppress unhandled-promise lint warnings:

void this.bannerService.success('Saved');

When to use

Capture the returned ref to react to banner dismissal or inspect the original config.

Example

Reacting to action dismissal with form values:

const ref = this.bannerService.warning('Update available', {
    actionsGroup: [
        { type: 'checkbox', key: 'autoUpdate', label: 'Auto-update' },
        { type: 'button', key: 'update', label: 'Update', appearance: 'filled' },
    ],
});

const result = await ref.result;

if (result.actionKey === 'update') {
    const autoUpdate = result.actionsGroupValues['autoUpdate'] as boolean;
    this.performUpdate(autoUpdate);
}

Example

Fire-and-forget:

void this.bannerService.success('Saved');

TbxMatBannerResult

Result returned when a banner is dismissed

Resolved by the TbxMatBannerRef.result promise when a banner is dismissed for any reason — user action, timeout, or programmatic dismissal. The dismissReason property indicates which trigger caused the dismissal. When an action button triggered the dismissal, actionKey identifies the button. Form control values from the actions group are collected in actionsGroupValues.

When to use

Await the result promise from any TbxMatBannerService method to determine how a banner was dismissed and retrieve collected values.

Example

const ref = this.bannerService.warning('Update available', {
    actionsGroup: [
        { type: 'checkbox', key: 'autoUpdate', label: 'Auto-update', defaultValue: false },
        { type: 'button', key: 'update', label: 'Update Now', appearance: 'filled' },
        { type: 'button', key: 'later', label: 'Later' },
    ],
});

const result: TbxMatBannerResult = await ref.result;

if (result.actionKey === 'update') {
    const autoUpdate = result.actionsGroupValues['autoUpdate'] as boolean;
    this.performUpdate(autoUpdate);
}

Enums

TbxMatBannerAnimation

Enter/exit animation mode for overlay banners

Controls the motion applied to an overlay banner as it appears and disappears. Values map to CSS classes defined in src/styles/_tbx-mat-banners.scss that drive keyframe animations on the CDK Overlay panel:

  • None — no animation. The banner appears and disappears instantly. - Slide — slides in from the closest viewport edge based on TbxMatBannerConfig.verticalPosition, and slides out the same way on dismiss. - Fade — fades in and out via opacity.

Consumers can tune motion timing via four CSS custom properties: --tbx-mat-banner-anim-enter-duration, --tbx-mat-banner-anim-enter-easing, --tbx-mat-banner-anim-exit-duration, and --tbx-mat-banner-anim-exit-easing. Animations are automatically disabled when the user has prefers-reduced-motion: reduce set at the OS level.

When to use

Set per banner via TbxMatBannerConfig.animation, or set an application-wide default via TbxMatBannerProviderConfig.defaultAnimation. A per-banner value always wins over the provider default.

Example

this.banner.success('Saved.', { animation: TbxMatBannerAnimation.Slide });

TbxMatBannerDismissReason

Reason a banner was dismissed

Returned as part of TbxMatBannerResult via TbxMatBannerRef.result. Each value corresponds to a distinct dismissal trigger:

  • Action — the user clicked an action button in the actions group. - Close — the user clicked the close button. - Timeout — the banner auto-dismissed after the configured duration expired. - ProgrammaticDismissAllTbxMatBannerService.dismissAll was called, clearing the queue and dismissing the active banner. - ProgrammaticDismissCurrentTbxMatBannerService.dismiss was called, dismissing only the currently active banner.

When to use

Inspect the dismiss reason after awaiting the result promise to determine which user or programmatic action closed the banner.

Example

const ref = this.bannerService.success('Item deleted', {
    actionsGroup: [{ type: 'button', key: 'undo', label: 'Undo' }],
    duration: 30_000,
});

const result = await ref.result;

if (result.dismissReason === TbxMatBannerDismissReason.Action) {
    this.undoDelete();
}

Types

TbxMatBannerActionButtonAppearance

Visual appearance of a banner action button

Union of MatButtonAppearance ('text' | 'filled' | 'elevated' | 'outlined' | 'tonal') and the custom 'icon' value for icon-only action buttons.

Values other than 'icon' map directly to the [appearance] input on Angular Material button directives. The 'icon' value renders a mat-icon-button instead.

This type is coupled to MatButtonAppearance from @angular/material/button. If Angular Material renames, removes, or adds values to that type, this type will need a corresponding update.

Each button in the actions group specifies its own appearance. When omitted, defaults to 'text'.

When to use

Specify the action button appearance when the default 'text' style is not desired.

Example

// Tonal action button
this.bannerService.warning('Connection lost', {
    actionsGroup: [{
        type: 'button',
        key: 'retry',
        label: 'Retry',
        appearance: 'tonal',
    }],
});

// Icon-only action button
this.bannerService.error('Upload failed', {
    actionsGroup: [{
        type: 'button',
        key: 'retry',
        label: 'Retry', // used as aria-label
        icon: 'refresh',
        appearance: 'icon',
    }],
});

TbxMatBannerActionsGroupControl

Discriminated union of all banner actions group control types

Each control in a banner's actionsGroup array must be one of these types. The type property serves as the discriminant for type narrowing in \@switch blocks and conditional logic.

Controls are rendered in the slot between the banner's message and close button, in array order.

  • 'button'TbxMatBannerActionButton — clickable button that dismisses the banner - 'checkbox'TbxMatBannerActionCheckbox — boolean checkbox control - 'toggle'TbxMatBannerActionToggle — slide toggle control - 'radio-group'TbxMatBannerActionRadioGroup — single-select radio group - 'toggle-group'TbxMatBannerActionToggleGroup — button toggle group (single or multi-select)

When to use

Use this type when declaring the actionsGroup array on TbxMatBannerConfig to ensure type safety across all control types.

Example

const actionsGroup: TbxMatBannerActionsGroupControl[] = [
    { type: 'checkbox', key: 'dontShowAgain', label: "Don't show again" },
    { type: 'button', key: 'dismiss', label: 'Dismiss' },
    { type: 'button', key: 'retry', label: 'Retry', appearance: 'filled' },
];

Accessibility

  • Overlay container. Overlay banners render inside a CDK Overlay pane positioned at the top or bottom of the viewport. The overlay is non-blocking and does not trap focus. Consumers that need screen-reader announcement of new banners should wrap the banner message in a container with aria-live="polite" in their application shell, or use the existing LiveAnnouncer service to announce the message text alongside the banner call.
  • Keyboard. The close button and every control in the actions group are focusable in DOM order. Enter and Space activate buttons; form controls use their native Angular Material keyboard behavior.
  • Focus. Focus is not moved into the banner automatically — banners are non-blocking. Consumers that need to direct attention to a banner action should call focus() on the control explicitly, or escalate to a dialog.
  • Reduced motion. When prefers-reduced-motion: reduce is set, the Slide and Fade animations are bypassed and banners show/hide instantly regardless of the configured animation.
  • Color contrast. The default severity palette meets WCAG AA contrast for body text on each background. Overriding the severity CSS custom properties is the consumer's responsibility to re-verify.
  • Icons. Severity icons are decorative and marked aria-hidden; the severity meaning is carried by the message text itself, not by the icon alone.