Logo

Toast

Stackable notifications with variants, actions, loading states, dismissal controls, positions, and RTL support.

Preview

Usage

HTML

<ng-template #toastCloseIcon>
  <ng-icon name="tablerX" />
</ng-template>

<frame-toast-viewport [closeIcon]="toastCloseIcon" />

TS

import { inject } from '@angular/core';
import { FrToastModule, FrToastService } from '@frame-ui-ng/components/toast';

private readonly toast = inject(FrToastService);

notify(): void {
  this.toast.show('Workspace synced', {
    description: 'All local changes are now available on the server.',
  });
}

Examples

Basic

Trigger a short notification from any component that can inject the service.

Variants

Use semantic variants for neutral, success, info, warning, and error states.

Card stack

Multiple calls layer into a compact card stack instead of replacing the previous message.

Action

Attach one optional action for undo, retry, open, or review flows.

Loading

Create a persistent loading toast and update it when the async work completes.

Dismissible

Disable the close button for pinned notices and dismiss them from code.

Position

Choose one of six viewport positions per toast.

RTL

The toast viewport inherits text direction from its surrounding container.

Custom Styling

Override toast tokens on the viewport or a wrapping element to brand one notification region without changing service calls.

Token Inspector

Inspect the toast surface, status marker, content stack, text, action, and close affordance. The preview renders persistent static toast markup instead of firing live page-level notifications.

Build published

The production bundle is available for review.

Title-only toast

Design tokens

Toast tokens control viewport placement, stack rhythm, panel surface, text, actions, close button, variants, and motion.

SCSS

--frame-toast-viewport-inset: 1rem;
--frame-toast-viewport-width: min(100vw - 2rem, 26rem);
--frame-toast-stack-offset: 0.875rem;
--frame-toast-stack-depth: 2.25rem;
--frame-toast-stack-scale-step: 0.025;
--frame-toast-stack-expanded-gap: 0.75rem;
--frame-toast-stack-expanded-depth: 28rem;
--frame-toast-padding: 0.875rem;
--frame-toast-gap: 0.75rem;
--frame-toast-radius: var(--frame-radius-lg);
--frame-toast-bg: var(--frame-surface);
--frame-toast-color: var(--frame-foreground);
--frame-toast-border: var(--frame-border);
--frame-toast-shadow: 0 18px 45px rgb(0 0 0 / 0.14);
--frame-toast-title-font-size: 0.875rem;
--frame-toast-title-font-weight: 650;
--frame-toast-description-font-size: 0.8125rem;
--frame-toast-description-color: var(--frame-muted-foreground);
--frame-toast-status-size: 0.625rem;
--frame-toast-status-bg: var(--frame-muted-foreground);
--frame-toast-action-bg: var(--frame-primary);
--frame-toast-action-color: var(--frame-primary-foreground);
--frame-toast-action-hover-bg: color-mix(in srgb, var(--frame-primary) 88%, black);
--frame-toast-action-radius: var(--frame-radius-md);
--frame-toast-close-size: 1.75rem;
--frame-toast-close-icon-size: 1rem;
--frame-toast-close-color: var(--frame-muted-foreground);
--frame-toast-close-hover-bg: var(--frame-accent);
--frame-toast-motion-duration: 180ms;
--frame-toast-motion-easing: cubic-bezier(0.16, 1, 0.3, 1);
--frame-toast-stack-transition-duration: 220ms;
--frame-toast-stack-transition-easing: cubic-bezier(0.16, 1, 0.3, 1);