Banners are the heavier-duty message surface in the @teqbench family — wider than a notification, can hold multi-line text, optional action buttons and form controls (checkboxes, toggles, radio groups), and dismisses only on an explicit user action or a programmatic call. The same package ships two ways to render one: an overlay produced by TbxMatBannerService (pinned to the viewport top or bottom via CDK Overlay) and an inline <tbx-mat-banner> component you embed directly in a template.
This guide assumes you already followed Install & authenticate and Configure the severity theme. The banner package peer-depends on the severity theme and picks up the same six-tier color palette.
Install the package
npm install @teqbench/tbx-mat-bannersProvide the banner config at bootstrap
Banners need a severity-icon resolver to draw the leading tier icon. The package ships two: TbxMatBannerSeverityFontIconService (Material Symbols ligatures) and TbxMatBannerSeveritySvgIconService (inline SVGs). Wire one via the TBX_MAT_BANNER_PROVIDER_CONFIG injection token in app.config.ts:
import { bootstrapApplication } from '@angular/platform-browser';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { provideTbxMatSeverityTheme } from '@teqbench/tbx-mat-severity-theme';
import {
TBX_MAT_BANNER_PROVIDER_CONFIG,
TbxMatBannerAnimation,
TbxMatBannerSeverityFontIconService,
} from '@teqbench/tbx-mat-banners';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [
provideAnimationsAsync(),
provideTbxMatSeverityTheme({ invert: false }),
{
provide: TBX_MAT_BANNER_PROVIDER_CONFIG,
useFactory: () => ({
severityIconResolverService: new TbxMatBannerSeverityFontIconService(
'material-symbols-rounded',
),
defaultAnimation: TbxMatBannerAnimation.Slide,
}),
},
],
});defaultAnimation is optional. When unset, banners default to TbxMatBannerAnimation.None (no transition). Per-banner animation still overrides whatever the provider picks.
Fire an overlay banner
Inject TbxMatBannerService and call a severity method:
import { Component, inject } from '@angular/core';
import { TbxMatBannerService } from '@teqbench/tbx-mat-banners';
@Component({
selector: 'app-upload-button',
template: `<button (click)="onFailed()">Simulate failure</button>`,
})
export class UploadButtonComponent {
private readonly banner = inject(TbxMatBannerService);
onFailed(): void {
void this.banner.error('Upload failed. Check your connection and retry.');
}
}The convenience methods (success / error / warning / information / help) each take a message string and an optional config. The call returns a TbxMatBannerRef synchronously — a leading void discards it when you don't need the handle. By default, an overlay banner pins to the viewport top, auto-dismiss is disabled (duration: 0), and both the severity icon and the close button are visible.
Customize a single call
The most common per-call overrides:
this.banner.warning('Connection unstable.', {
verticalPosition: 'bottom',
animation: TbxMatBannerAnimation.Fade,
duration: 6000,
});
this.banner.information('Release notes ready.', {
showSeverityIcon: false,
});duration works the same as notifications — <= 0 (or omitted) means indefinite; > 0 auto-dismisses after that many ms. verticalPosition is 'top' or 'bottom'. animation accepts TbxMatBannerAnimation.None | .Slide | .Fade. Animations respect the user's prefers-reduced-motion setting automatically.
Add an actions group
Every call can include an actionsGroup — an ordered array of buttons and form controls rendered between the message and the close button. The simplest case is a single button:
this.banner.success('Item deleted.', {
duration: 30_000,
actionsGroup: [
{ type: 'button', key: 'undo', label: 'Undo', appearance: 'tonal' },
],
});Clicking a button dismisses the banner and resolves the ref's result promise with dismissReason: Action and actionKey: 'undo'.
Buttons and form controls mix freely. An update prompt with an "auto-update" toggle:
this.banner.information('An update is available.', {
actionsGroup: [
{ type: 'toggle', key: 'autoUpdate', label: 'Auto-update from now on' },
{ type: 'button', key: 'later', label: 'Later' },
{ type: 'button', key: 'update', label: 'Update now', appearance: 'filled' },
],
});Form controls (checkbox, toggle, radio-group, toggle-group) don't dismiss — only buttons do. When a button dismisses the banner, every control's current value is snapshotted into result.actionsGroupValues, keyed by its key:
const ref = this.banner.information('An update is available.', {
actionsGroup: [
{ type: 'toggle', key: 'autoUpdate', label: 'Auto-update' },
{ type: 'button', key: 'update', label: 'Update now' },
],
});
const result = await ref.result;
if (result.actionKey === 'update') {
const autoUpdate = result.actionsGroupValues['autoUpdate'] as boolean;
await this.applyUpdate({ schedule: autoUpdate });
}Checkbox and toggle values are boolean. Radio-group and single-select toggle-group values are string | undefined. Multi-select toggle-group values are string[].
React to dismissal
Same pattern as notifications — await ref.result and switch on the reason:
import {
TbxMatBannerDismissReason,
TbxMatBannerService,
} from '@teqbench/tbx-mat-banners';
async onDelete(id: string): Promise<void> {
const ref = this.banner.success('Item deleted.', {
duration: 30_000,
actionsGroup: [
{ type: 'button', key: 'undo', label: 'Undo' },
],
});
const result = await ref.result;
switch (result.dismissReason) {
case TbxMatBannerDismissReason.Action:
if (result.actionKey === 'undo') await this.restore(id);
break;
case TbxMatBannerDismissReason.Close:
case TbxMatBannerDismissReason.Timeout:
// User let it expire — nothing to do.
break;
}
}The full reason enum (Action, Close, Timeout, ProgrammaticDismissAll, ProgrammaticDismissCurrent) mirrors the notification API.
Dismiss programmatically
this.banner.dismiss(); // close the active banner (queued ones stay)
this.banner.dismissAll(); // clear queue + close activeQueued banners cleared by dismissAll() resolve their ref.result with ProgrammaticDismissAll without ever having rendered.
Render a banner inline
For a banner that sits inside a specific component's layout (rather than floating over the viewport), use the <tbx-mat-banner> component directly. It takes signal inputs for every config field and emits a dismissed event carrying the same TbxMatBannerResult:
import { Component, inject } from '@angular/core';
import {
TbxMatBannerComponent,
TbxMatBannerDismissReason,
TbxMatBannerResult,
} from '@teqbench/tbx-mat-banners';
import { TbxMatSeverityLevel } from '@teqbench/tbx-mat-severity-theme';
@Component({
selector: 'app-offline-notice',
imports: [TbxMatBannerComponent],
template: `
<tbx-mat-banner
[type]="severity"
[message]="message"
[actionsGroup]="actions"
(dismissed)="onDismiss($event)"
/>
`,
})
export class OfflineNoticeComponent {
readonly severity = TbxMatSeverityLevel.Warning;
readonly message = 'You are currently offline. Some data may be out of date.';
readonly actions = [
{ type: 'button' as const, key: 'retry', label: 'Retry', appearance: 'tonal' as const },
];
onDismiss(result: TbxMatBannerResult): void {
if (result.dismissReason === TbxMatBannerDismissReason.Action && result.actionKey === 'retry') {
this.retryConnection();
}
}
private retryConnection(): void {
/* … */
}
}The inline component carries the severity panel class on its host automatically, so the severity-theme tokens apply without any extra styling on your side. verticalPosition, animation, and panelClass are overlay-only fields — ignored in inline mode because there's no overlay frame around the component.
What to try next
- Custom icons — swap the shipped severity icon service for your own brand glyphs via Use Material Symbols ligatures or Register inline SVG icons.
- Scoped inversion — render a single dialog with the inverted palette (colored text on white) via Scoped inverted palette.
- Error logging — swap the default error logger when you want banner-triggering errors to flow through Sentry or Datadog, via Plug in a custom ErrorLogger.