README.md

March 13, 2026 · View on GitHub



 ███╗   ██╗ ██████╗ ██╗  ██╗      ███████╗██╗ ██████╗ ███╗  ██╗ █████╗ ██╗
 ████╗  ██║██╔════╝ ╚██╗██╔╝      ██╔════╝██║██╔════╝ ████╗ ██║██╔══██╗██║
 ██╔██╗ ██║██║  ███╗ ╚███╔╝ █████╗███████╗██║██║  ███╗██╔██╗██║███████║██║
 ██║╚██╗██║██║   ██║ ██╔██╗ ╚════╝╚════██║██║██║   ██║██║╚████║██╔══██║██║
 ██║ ╚████║╚██████╔╝██╔╝ ██╗      ███████║██║╚██████╔╝██║ ╚███║██║  ██║███████╗
 ╚═╝  ╚═══╝ ╚═════╝ ╚═╝  ╚═╝      ╚══════╝╚═╝ ╚═════╝ ╚═╝  ╚══╝╚═╝  ╚═╝╚══════╝

 ████████╗ ██████╗  █████╗ ███████╗████████╗
    ██║   ██╔═══██╗██╔══██╗██╔════╝╚══██╔══╝
    ██║   ██║   ██║███████║███████╗   ██║
    ██║   ██║   ██║██╔══██║╚════██║   ██║
    ██║   ╚██████╔╝██║  ██║███████║   ██║
    ╚═╝    ╚═════╝ ╚═╝  ╚═╝╚══════╝   ╚═╝

The most powerful Angular 21 toast library — built entirely on Signals

Zero @angular/animations · Zero Zone.js dependency · Zero HTML tags to add

🚀 Quick Start · 📖 API Reference · 🎨 Themes · 💡 Examples · ⚙️ Configuration



📋 Table of Contents


🤔 Why ngx-signal-toast?

🆚 Comparison with Other Toast Libraries

Featurengx-signal-toastngx-toastrhot-toast
Angular 21 native
Signals-first (no RxJS)
Zoneless compatible
@angular/animations free
Auto-inject container
8 built-in themes
6 layout styles
9 positions
Native CSS animations
SSR safe⚠️⚠️
Zero dependencies
Promise API
TypeScript 5.5+⚠️⚠️

✨ Features

  • 🎯 100% Signals — built with signal(), computed(), effect() — no RxJS at all
  • Zoneless Ready — works perfectly with Angular's new zoneless change detection
  • 🎨 8 Beautiful Themes — Default, Glassmorphism, Neumorphism, Aurora, Neon, Luxury, Material, Brutalist
  • 📐 6 Layout Styles — Default, Compact, Card, Pill, Sidebar, Banner
  • 📍 9 Positions — all corners, edges, and center
  • 🎬 5 Animation Presets — Slide, Fade, Bounce, Zoom, Flip — all via native CSS (no @angular/animations)
  • 🔄 Promise API — loading → success/error in one call
  • ⏸️ Pause on Hover — progress bar pauses when user hovers
  • 🎯 Action Buttons — add interactive buttons inside any toast
  • 📝 Update in Flight — update message/type/duration of an active toast
  • 🌍 RTL Support — full right-to-left text support
  • ARIA compliantrole="alert", aria-live, aria-label built-in
  • 🖥️ SSR SafeisPlatformBrowser guards throughout
  • 🎭 Custom Icons — emoji, component, or template ref
  • 🎨 Custom Body — inject your own component as toast body
  • 🔗 Auto-inject — no <nst-toast-container> HTML tag needed
  • 📦 ~0 extra dependencies — only @angular/core and @angular/common

📌 Version & Requirements

PackageVersion
ngx-signal-toast1.1.0
@angular/core>= 21.0.0
@angular/common>= 21.0.0
TypeScript>= 5.5
Node.js>= 20.0.0

⚠️ Angular 21 only. This library uses APIs introduced in Angular 21 (provideAppInitializer, signals-first DI). It will not work on older versions.


📦 Installation

# npm
npm install ngx-signal-toast

# yarn
yarn add ngx-signal-toast

# pnpm
pnpm add ngx-signal-toast
ng add ngx-signal-toast

The schematic will automatically:

  • Add provideNgxSignalToast() to your app.config.ts
  • Ask you to choose a default theme and position

🚀 Quick Start

Step 1 — Register the provider

Open app.config.ts and add provideNgxSignalToast():

// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideNgxSignalToast } from 'ngx-signal-toast';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideNgxSignalToast({
      position: 'top-right',
      duration: 4000,
      theme: 'default',
    }),
  ],
};

✅ That's it. No <nst-toast-container> tag needed anywhere. The container is automatically injected into document.body.

Step 2 — Inject and use

// any.component.ts
import { Component, inject } from '@angular/core';
import { ToastService } from 'ngx-signal-toast';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `<button (click)="showToast()">Show Toast</button>`,
})
export class AppComponent {
  private toast = inject(ToastService);

  showToast() {
    this.toast.success('Operation completed successfully!');
  }
}

🔧 Basic Usage

import { Component, inject } from '@angular/core';
import { ToastService } from 'ngx-signal-toast';

@Component({ ... })
export class MyComponent {
  private toast = inject(ToastService);

  // Basic types
  showSuccess() { this.toast.success('Saved successfully!'); }
  showError()   { this.toast.error('Something went wrong.'); }
  showWarning() { this.toast.warning('Please review your input.'); }
  showInfo()    { this.toast.info('Update available.'); }
  showLoading() { this.toast.loading('Loading your data...'); }

  // With a title
  showWithTitle() {
    this.toast.success('Your file has been uploaded.', {
      title: 'Upload Complete',
    });
  }

  // Custom duration (milliseconds)
  showLong() {
    this.toast.info('This stays for 10 seconds.', { duration: 10000 });
  }

  // Permanent (never auto-dismiss)
  showPermanent() {
    this.toast.warning('Action required.', { duration: 0 });
  }
}

🎯 Toast Types

MethodIconDefault ColorUse Case
toast.success(msg)✓ checkmarkGreen #22c55eOperation completed
toast.error(msg)✗ crossRed #f43f5eSomething failed
toast.warning(msg)⚠ triangleAmber #f59e0bNeeds attention
toast.info(msg)ℹ circleBlue #3b82f6Informational
toast.loading(msg)⟳ spinnerPurple #8b5cf6Async operation
toast.show(msg, opts)★ starPink #ec4899Custom / flexible

⚙️ Configuration

Pass options to provideNgxSignalToast() to set global defaults. Every option can be overridden per-toast.

provideNgxSignalToast({
  position:     'top-right',      // where toasts appear
  duration:     4000,             // auto-dismiss in ms (0 = never)
  theme:        'default',        // visual theme
  layout:       'default',        // layout style
  animation:    'slide',          // enter/leave animation
  maxToasts:    5,                // max visible at once
  showProgress: true,             // show countdown bar
  pauseOnHover: true,             // pause timer on hover
  closeOnClick: false,            // dismiss on toast click
  closable:     true,             // show close button
  dedupe:       false,            // prevent duplicate messages
  rtl:          false,            // right-to-left mode
  zIndex:       9999,             // CSS z-index of container
})

📚 All Options Reference

Global Config Options (provideNgxSignalToast)

OptionTypeDefaultDescription
positionToastPosition'top-right'Where toasts appear on screen
durationnumber4000Auto-dismiss time in ms. 0 = never
themeToastTheme'default'Visual theme
layoutToastLayout'default'Layout style
animationToastAnimationPreset'slide'Enter/leave animation
maxToastsnumber5Max toasts visible at once
showProgressbooleantrueShow countdown progress bar
pauseOnHoverbooleantruePause timer when hovering
closeOnClickbooleanfalseDismiss when toast is clicked
closablebooleantrueShow the × close button
dedupebooleanfalseSuppress duplicate messages
rtlbooleanfalseRight-to-left text direction
zIndexnumber9999CSS z-index of toast container

Per-Toast Options (ToastOptions)

All global options above plus:

OptionTypeDefaultDescription
idstringautoCustom ID for the toast
titlestring''Bold title above the message
typeToastType'info'Toast type (success/error/warning/info/loading/custom)
groupstring''Group name for bulk dismiss
hideIconbooleanfalseHide the type icon
iconEmojistringShow an emoji as icon
iconComponentType<any>Angular component as icon
iconTemplateTemplateRefTemplate ref as icon
bodyComponentType<any>Replace entire body with component
ariaLabelstringmessageAccessibility label
dataanyAttach any custom data
stylesToastCustomStylesPer-toast style overrides
actionsToastAction[][]Action buttons inside toast
onOpen() => voidCallback when toast appears
onClose() => voidCallback when toast dismisses

ToastCustomStyles

PropertyTypeDescription
accentColorstringIcon and accent color (hex/rgb/hsl)
backgroundstringToast background color
borderColorstringBorder color
borderRadiusstring | numberBorder radius (px or CSS string)
titleColorstringTitle text color
messageColorstringMessage text color
iconBackgroundstringIcon wrapper background

🎨 Themes

Set globally or per-toast with theme: 'theme-name'.

ThemeDescription
defaultClean, modern dark card with subtle shadow
glassmorphismFrosted glass with blur and transparency
neumorphismSoft shadow depth, tactile feel
auroraGradient border, northern-lights inspired
neonGlowing neon borders on dark background
luxuryGold accents, premium feel
materialGoogle Material Design style
brutalistRaw, bold, high-contrast editorial style
// Per-toast theme override
this.toast.success('Uploaded!', { theme: 'glassmorphism' });
this.toast.error('Failed!',     { theme: 'neon' });
this.toast.info('Note',         { theme: 'luxury' });

📐 Layouts

LayoutDescription
defaultStandard card with icon, title, message
compactSlim single-line with small icon
cardColored top border accent bar
pillRounded pill shape, centered content
sidebarLeft colored stripe accent
bannerFull-width banner style
this.toast.info('Compact notification', { layout: 'compact' });
this.toast.success('Card style!',        { layout: 'card' });
this.toast.warning('Full width alert',   { layout: 'banner' });

📍 Positions

9 positions covering the entire viewport:

┌─────────────────────────────────────┐
│  top-left   top-center   top-right  │
│                                     │
│ center-left   center   center-right │
│                                     │
│ bottom-left bottom-center bot-right │
└─────────────────────────────────────┘
PositionValue
Top Left'top-left'
Top Center'top-center'
Top Right'top-right'
Center Left'center-left'
Center'center'
Center Right'center-right'
Bottom Left'bottom-left'
Bottom Center'bottom-center'
Bottom Right'bottom-right'
// Different positions per toast
this.toast.success('Top right',     { position: 'top-right' });
this.toast.error('Bottom center',   { position: 'bottom-center' });
this.toast.info('Center screen',    { position: 'center' });

🎬 Animations

All animations use native CSS — no @angular/animations package required.

PresetEnterLeave
slideSlides down from top + fade inSlides up + fade out
fadeFade in + slight scaleFade out + scale down
bounceSpring overshoot effectShrink + fade
zoomScale from 50%Scale to 50% + fade
flip3D perspective rotateRotate back + fade
this.toast.success('Bouncy!', { animation: 'bounce' });
this.toast.info('Flipping in', { animation: 'flip' });
this.toast.error('Zoomed', { animation: 'zoom' });

Accessibility: All animations are automatically disabled when the user has prefers-reduced-motion: reduce set in their OS settings.


🔘 Toast Actions

Add interactive buttons directly inside a toast:

this.toast.warning('Unsaved changes detected.', {
  title: 'Confirm Action',
  duration: 0,
  actions: [
    {
      label: 'Save',
      onClick: (id) => {
        this.saveData();
        // Toast auto-dismisses after action by default
      },
    },
    {
      label: 'Discard',
      style: 'danger',   // red danger style
      onClick: (id) => {
        this.discardChanges();
      },
      closeOnClick: true,
    },
  ],
});

ToastAction Options

PropertyTypeDefaultDescription
labelstringrequiredButton text
onClick(id: string) => voidrequiredClick handler
style'default' | 'danger''default'Button style
closeOnClickbooleantrueAuto-dismiss on click

🔄 Promise Toast

Show loading → automatically switch to success or error when the promise resolves:

// Basic promise
await this.toast.promise(
  this.apiService.saveData(payload),
  {
    loading: 'Saving your data...',
    success: 'Saved successfully!',
    error:   'Failed to save. Please try again.',
  }
);

// With dynamic messages based on result
await this.toast.promise(
  this.userService.createUser(form),
  {
    loading: 'Creating account...',
    success: (user) => `Welcome, ${user.name}!`,
    error:   (err)  => `Error: ${err.message}`,
  },
  {
    position: 'top-center',
    theme: 'glassmorphism',
  }
);

⏳ Loading Toast

For long-running async operations you control manually:

// Show loading toast — returns a ToastRef
const ref = this.toast.loading('Uploading file...');

try {
  await this.uploadService.upload(file, (progress) => {
    // Update the message dynamically
    ref.update({ message: `Uploading... ${progress}%` });
  });

  // Switch to success when done
  ref.update({
    type: 'success',
    message: 'File uploaded successfully!',
    duration: 4000,  // now auto-dismiss
  });

} catch (error) {
  // Switch to error on failure
  ref.update({
    type: 'error',
    message: 'Upload failed. Please try again.',
    duration: 5000,
  });
}

🎭 Custom Icons

Emoji Icon

this.toast.success('Great job!', {
  iconEmoji: '🎉',
});

this.toast.info('Check this out', {
  iconEmoji: '👀',
});

Angular Component as Icon

@Component({
  standalone: true,
  template: `<svg ...><!-- your SVG --></svg>`,
})
export class MyIconComponent {}

// Use it
this.toast.success('Custom icon!', {
  iconComponent: MyIconComponent,
});

Template Ref as Icon

<ng-template #starIcon>
  <span class="material-icons">star</span>
</ng-template>
@ViewChild('starIcon') starIcon!: TemplateRef<any>;

showToast() {
  this.toast.success('Starred!', {
    iconTemplate: this.starIcon,
  });
}

Hide Icon Entirely

this.toast.info('No icon here', { hideIcon: true });

🖌️ Custom Styles

Override appearance per-toast using the styles option:

// Custom brand colors
this.toast.show('Custom branded toast!', {
  type: 'custom',
  styles: {
    accentColor:    '#FF6B6B',
    background:     '#1A1A2E',
    borderColor:    '#FF6B6B',
    borderRadius:   20,
    titleColor:     '#FFFFFF',
    messageColor:   '#CCCCCC',
    iconBackground: 'rgba(255,107,107,0.15)',
  },
});

// Combine with emoji icon
this.toast.show('🚀 Deployment triggered!', {
  type: 'custom',
  title: 'CI/CD Pipeline',
  iconEmoji: '🚀',
  styles: {
    accentColor: '#6C63FF',
    background: '#0F0F23',
  },
});

🎯 ToastRef — Update & Dismiss

Every toast.*() method returns a ToastRef for programmatic control:

const ref = this.toast.info('Processing...', { duration: 0 });

// Update any property of the active toast
ref.update({
  message: 'Almost done...',
  type: 'success',
  duration: 3000,   // starts auto-dismiss countdown
});

// Dismiss programmatically
ref.dismiss();

// Check the ID
console.log(ref.id); // 'nst-1-1234567890'

ToastRef API

MethodDescription
ref.idUnique string ID of this toast
ref.update(patch)Update any toast option on the fly
ref.dismiss()Dismiss this toast immediately

🗂️ Service Methods

// Show methods
toast.success(message, options?)  // → ToastRef
toast.error(message, options?)    // → ToastRef
toast.warning(message, options?)  // → ToastRef
toast.info(message, options?)     // → ToastRef
toast.loading(message, options?)  // → ToastRef
toast.show(message, options?)     // → ToastRef

// Promise helper
toast.promise(promise, messages, options?)  // → Promise<T>

// Dismiss methods
toast.dismiss(id)           // dismiss one by ID
toast.dismissAll()          // dismiss all visible toasts
toast.dismissByType('error')  // dismiss all of a type
toast.dismissByGroup('auth')  // dismiss by group name

// State signals (read-only)
toast.toasts()     // Signal<Toast[]>
toast.count()      // Signal<number>
toast.isEmpty()    // Signal<boolean>

🎨 CSS Variables

Customize the look globally using CSS custom properties in your styles.css:

:root {
  /* Layout */
  --nst-gap:    10px;   /* gap between stacked toasts */

  /* Per-theme overrides */
  --nst-bg:     #1f2937;
  --nst-color:  #f9fafb;
  --nst-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
  --nst-radius: 14px;
  --nst-border: none;
  --nst-font:   'Your Font', system-ui, sans-serif;
}

🖥️ SSR Support

ngx-signal-toast is fully SSR-safe. All browser APIs are guarded with isPlatformBrowser. The container is only injected in browser environments. No extra configuration needed for Angular Universal or any SSR setup.

// Works in SSR — library handles this internally
provideNgxSignalToast({ theme: 'default' })

♿ Accessibility

FeatureImplementation
ARIA rolesrole="alert" for errors, role="status" for others
Live regionsaria-live="assertive" for errors, aria-live="polite" for others
Labelsaria-label on every toast (defaults to message text)
Close buttonaria-label="Close notification"
Reduced motionAll animations disabled via @media (prefers-reduced-motion: reduce)
RTL supportFull direction: rtl support via rtl: true option
Focus managementClose button focusable with keyboard

💡 Examples

E-commerce — Cart Notification

addToCart(product: Product) {
  this.cartService.add(product);
  this.toast.success(`${product.name} added to cart`, {
    title: 'Cart Updated',
    layout: 'card',
    theme: 'default',
    iconEmoji: '🛒',
    duration: 3000,
    actions: [{
      label: 'View Cart',
      onClick: () => this.router.navigate(['/cart']),
    }],
  });
}

Auth — Login Flow

async login(credentials: LoginForm) {
  await this.toast.promise(
    this.authService.login(credentials),
    {
      loading: 'Signing you in...',
      success: (user) => `Welcome back, ${user.firstName}!`,
      error: 'Invalid email or password.',
    },
    { position: 'top-center', theme: 'glassmorphism' }
  );
}

File Upload with Progress

async uploadFile(file: File) {
  const ref = this.toast.loading(`Uploading ${file.name}...`, {
    duration: 0,
    closable: false,
  });

  try {
    await this.fileService.upload(file, (pct) => {
      ref.update({ message: `Uploading ${file.name}... ${pct}%` });
    });
    ref.update({ type: 'success', message: 'Upload complete!', duration: 3000 });
  } catch {
    ref.update({ type: 'error', message: 'Upload failed.', duration: 5000 });
  }
}

Bulk Dismiss by Group

// Show several related toasts with a group name
this.toast.info('Step 1 complete', { group: 'wizard' });
this.toast.info('Step 2 complete', { group: 'wizard' });
this.toast.info('Step 3 complete', { group: 'wizard' });

// Later dismiss them all at once
this.toast.dismissByGroup('wizard');

RTL Support (Arabic / Hebrew)

// Set globally
provideNgxSignalToast({ rtl: true })

// Or per toast
this.toast.success('تم الحفظ بنجاح', { rtl: true });

Custom Full Body Component

@Component({
  standalone: true,
  template: `
    <div style="padding: 16px; display: flex; gap: 12px; align-items: center">
      <img src="/avatar.png" width="40" height="40" style="border-radius: 50%" />
      <div>
        <strong>John sent you a message</strong>
        <p style="margin: 0; opacity: 0.8; font-size: 13px">Hey, are you free today?</p>
      </div>
    </div>
  `,
})
export class MessageToastComponent {}

// Use it
this.toast.show('', {
  bodyComponent: MessageToastComponent,
  duration: 6000,
  theme: 'glassmorphism',
});

Reading Toast State in Template

@Component({
  template: `
    @if (!toast.isEmpty()) {
      <span>{{ toast.count() }} active notifications</span>
    }
    <button (click)="toast.dismissAll()">Clear All</button>
  `
})
export class NotificationBarComponent {
  toast = inject(ToastService);
}

📦 TypeScript Types

import type {
  Toast,
  ToastRef,
  ToastOptions,
  ToastConfig,
  ToastAction,
  ToastCustomStyles,
  ToastType,           // 'success' | 'error' | 'warning' | 'info' | 'loading' | 'custom'
  ToastPosition,       // 'top-left' | 'top-center' | 'top-right' | ...
  ToastTheme,          // 'default' | 'glassmorphism' | 'neumorphism' | ...
  ToastLayout,         // 'default' | 'compact' | 'card' | 'pill' | 'sidebar' | 'banner'
  ToastAnimationPreset // 'slide' | 'fade' | 'bounce' | 'zoom' | 'flip'
} from 'ngx-signal-toast';

📝 Changelog

v1.1.0

  • 🎬 Migrated from @angular/animations to native CSS animations
  • ✅ Removed @angular/animations peer dependency entirely
  • 🔧 Auto-inject container via provideAppInitializer — no HTML tag needed
  • 🔁 Split ToastStateService to resolve circular dependency (NG0200)
  • 🌀 Fixed spinner animation interrupted by mouse interaction
  • ♿ Added prefers-reduced-motion support

v1.0.0

  • 🎉 Initial release
  • 8 themes, 6 layouts, 9 positions, 5 animations
  • Full Signals API, Promise helper, Toast actions
  • SSR support, RTL support

🤝 Contributing

Contributions are welcome! Please open an issue first to discuss what you would like to change.

# Clone and install
git clone https://github.com/your-org/ngx-signal-toast.git
cd ngx-signal-toast
npm install

# Build the library
ng build ngx-signal-toast --configuration production

# Run the demo
ng serve demo

# Run tests
ng test ngx-signal-toast

📄 License

MIT © 2025 ngx-signal-toast


Made with ❤️ for the Angular community

⭐ Support the Project

If you find this library useful:

⭐ Star the repository
🐛 Report issues
💡 Suggest features
🤝 Contribute improvements