ng-toast-alerts
v1.0.3
Published
A lightweight Angular toast notification and alert library with simple integration and customizable messages.
Maintainers
Readme
ng-toast-alerts
A lightweight, zero-dependency Angular toast notification library with support for NgModule and Standalone apps.
Table of Contents
- Features
- Requirements
- Installation
- Setup
- Basic Usage
- Toast Types
- API Reference
- Real-World Examples
- Accessibility
- Styling & Customization
- FAQ
- Changelog
- License
Features
- ✅ 4 toast types — success, error, warning, info
- ⏱ Auto-dismiss — configurable per toast, or disable it entirely
- 📚 Stackable — multiple toasts appear simultaneously
- 🎨 Progress bar — animated countdown shows how long the toast has left
- ♿ Accessible — uses
aria-live,role="alert", and proper focus management - 📦 Works everywhere — NgModule apps, Standalone apps, lazy-loaded modules
- 🚫 Zero dependencies — no extra packages, just Angular + RxJS (already in your project)
- 🪶 Tiny — ~15KB unpacked
Requirements
| Package | Minimum version |
|---|---|
| @angular/core | 15.0.0 |
| @angular/common | 15.0.0 |
| rxjs | 7.0.0 |
Angular 15, 16, and 17 are all supported.
Installation
npm install ng-toast-alertsSetup
Option A — NgModule-based app (classic)
This is the setup for apps that use AppModule.
Step 1 — Import the module in app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgToastAlertsModule } from 'ng-toast-alerts';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
NgToastAlertsModule.forRoot() // always call forRoot() in AppModule only
],
bootstrap: [AppComponent]
})
export class AppModule {}Important: Only call
forRoot()inAppModule. Do not call it in feature or lazy-loaded modules — this would create a second instance ofToastService.
Step 2 — Add the container to app.component.html
<!-- Place this once at the root level of your app -->
<ng-toast-container></ng-toast-container>
<router-outlet></router-outlet>Option B — Standalone app (Angular 15+)
This is the setup for apps bootstrapped with bootstrapApplication.
Step 1 — Register the service in main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { ToastService } from 'ng-toast-alerts';
bootstrapApplication(AppComponent, {
providers: [
ToastService // registers the singleton
]
});Step 2 — Import the container component in app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ToastContainerComponent } from 'ng-toast-alerts';
@Component({
selector: 'app-root',
standalone: true,
imports: [
RouterOutlet,
ToastContainerComponent // add this
],
template: `
<ng-toast-container></ng-toast-container>
<router-outlet></router-outlet>
`
})
export class AppComponent {}Basic Usage
Inject ToastService into any component, service, guard, or interceptor and call the notification methods.
import { Component } from '@angular/core';
import { ToastService } from 'ng-toast-alerts';
@Component({
selector: 'app-example',
template: `
<button (click)="onSave()">Save</button>
<button (click)="onDelete()">Delete</button>
`
})
export class ExampleComponent {
constructor(private toast: ToastService) {}
onSave(): void {
this.toast.success('Your changes have been saved.');
}
onDelete(): void {
this.toast.error('Failed to delete item.', { title: 'Error' });
}
}Toast Types
There are four built-in toast types, each with its own color and icon.
| Type | Method | Color | Icon | Default Duration |
|---|---|---|---|---|
| Success | toast.success() | Green #22c55e | ✔ | 3000ms |
| Error | toast.error() | Red #ef4444 | ✖ | 5000ms |
| Warning | toast.warning() | Amber #f59e0b | ⚠ | 3000ms |
| Info | toast.info() | Blue #3b82f6 | ℹ | 3000ms |
Error toasts default to 5 seconds (instead of 3) because errors usually need more reading time.
API Reference
ToastService
The main service you inject and use throughout your application.
success(message, options?)
Shows a green success notification.
this.toast.success('Profile updated successfully.');
// with options
this.toast.success('File uploaded.', {
title: 'Upload Complete',
duration: 4000
});error(message, options?)
Shows a red error notification. Defaults to 5000ms duration.
this.toast.error('Could not connect to the server.');
// with options
this.toast.error('Invalid email or password.', {
title: 'Login Failed',
duration: 7000
});warning(message, options?)
Shows an amber warning notification.
this.toast.warning('Your session will expire in 5 minutes.');
// with options
this.toast.warning('Unsaved changes will be lost.', {
title: 'Warning',
duration: 0 // stays until user dismisses it
});info(message, options?)
Shows a blue informational notification.
this.toast.info('A new version of the app is available.');
// with options
this.toast.info('Scheduled maintenance at midnight.', {
title: 'Notice',
duration: 6000
});dismiss(id)
Manually dismisses a specific toast by its ID. The ID is returned from each toast method call. Useful when you want programmatic control over when a toast disappears.
// save the returned id
const id = this.toast.info('Processing your request...', { duration: 0 });
// later, when done — dismiss it
this.apiService.process().subscribe(() => {
this.toast.dismiss(id);
this.toast.success('Done!');
});Note: In the current version, toast methods return
void. To usedismiss(id)programmatically, subscribe totoasts$to find the ID, or useclear()instead.
clear()
Dismisses all active toasts immediately.
this.toast.clear();Useful when navigating away from a page and you want to clean up all pending notifications.
toasts$
An Observable<Toast[]> that emits the current list of active toasts. The ToastContainerComponent subscribes to this internally, but you can also use it yourself for custom rendering.
import { ToastService, Toast } from 'ng-toast-alerts';
export class MyComponent {
toasts$ = this.toast.toasts$;
constructor(private toast: ToastService) {}
}ToastOptions
An optional configuration object passed as the second argument to any toast method.
interface ToastOptions {
title?: string;
duration?: number;
}| Property | Type | Default | Description |
|---|---|---|---|
| title | string | undefined | Optional bold heading shown above the message |
| duration | number | 3000 (error: 5000) | Time in milliseconds before the toast auto-dismisses. Set to 0 to keep it open until the user closes it manually |
Examples:
// no options — uses defaults
this.toast.success('Done!');
// with title only
this.toast.error('Something went wrong.', { title: 'Error' });
// with custom duration
this.toast.warning('Low disk space.', { duration: 10000 });
// persistent — never auto-dismisses
this.toast.info('You have 3 unread messages.', { duration: 0 });
// both title and duration
this.toast.success('Report generated.', {
title: 'Export Complete',
duration: 5000
});Toast Interface
Each toast object has the following shape. You usually don't work with this directly unless building a custom container.
interface Toast {
id: string; // unique id like "toast-1694512345678-abc12"
message: string; // the notification text
type: ToastType; // 'success' | 'error' | 'warning' | 'info'
duration: number; // auto-dismiss time in ms (0 = persistent)
title?: string; // optional heading
}
type ToastType = 'success' | 'error' | 'warning' | 'info';ToastContainerComponent
The UI component that renders all active toasts. Place it once at the root of your app.
<ng-toast-container></ng-toast-container>Selector: ng-toast-container
Behavior:
- Toasts stack vertically from bottom-right
- New toasts appear with a slide-in animation from the right
- Each toast has a shrinking progress bar showing time remaining
- Clicking × on a toast dismisses it immediately
- Toasts disappear automatically after their duration
You do not need to pass any inputs — it subscribes to ToastService automatically.
NgToastAlertsModule
For NgModule-based apps. Always use forRoot() when importing in AppModule.
NgToastAlertsModule.forRoot()Exports: ToastContainerComponent
Provides: ToastService (singleton)
Real-World Examples
HTTP Interceptor — show error toasts on failed API calls
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpErrorResponse } from '@angular/common/http';
import { catchError, throwError } from 'rxjs';
import { ToastService } from 'ng-toast-alerts';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(private toast: ToastService) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
return next.handle(req).pipe(
catchError((error: HttpErrorResponse) => {
const message = error.error?.message || 'An unexpected error occurred.';
this.toast.error(message, { title: `Error ${error.status}` });
return throwError(() => error);
})
);
}
}Form submit — success and error feedback
@Component({ ... })
export class ContactFormComponent {
form = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
message: ['', Validators.required]
});
constructor(
private fb: FormBuilder,
private api: ContactService,
private toast: ToastService
) {}
submit(): void {
if (this.form.invalid) {
this.toast.warning('Please fill in all required fields.', { title: 'Validation' });
return;
}
this.api.send(this.form.value).subscribe({
next: () => {
this.toast.success('Your message has been sent!', { title: 'Thank you' });
this.form.reset();
},
error: () => {
this.toast.error('Could not send your message. Please try again.', { title: 'Failed' });
}
});
}
}Auth guard — inform user why they were redirected
import { inject } from '@angular/core';
import { Router, CanActivateFn } from '@angular/router';
import { AuthService } from './auth.service';
import { ToastService } from 'ng-toast-alerts';
export const authGuard: CanActivateFn = () => {
const auth = inject(AuthService);
const router = inject(Router);
const toast = inject(ToastService);
if (auth.isLoggedIn()) {
return true;
}
toast.warning('Please log in to access this page.', { title: 'Access Denied' });
router.navigate(['/login']);
return false;
};Route change — clear toasts on navigation
import { Component, OnInit } from '@angular/core';
import { Router, NavigationStart } from '@angular/router';
import { filter } from 'rxjs';
import { ToastService } from 'ng-toast-alerts';
@Component({
selector: 'app-root',
template: `
<ng-toast-container></ng-toast-container>
<router-outlet></router-outlet>
`
})
export class AppComponent implements OnInit {
constructor(
private router: Router,
private toast: ToastService
) {}
ngOnInit(): void {
this.router.events
.pipe(filter(e => e instanceof NavigationStart))
.subscribe(() => this.toast.clear());
}
}Accessibility
ng-toast-alerts is built with accessibility in mind:
- The container uses
aria-live="polite"so screen readers announce new toasts without interrupting the user - Each toast has
role="alert"for immediate screen reader announcement when needed - Each toast includes an
aria-labeldescribing its type and message - The dismiss button has
aria-label="Dismiss notification"for screen readers - Color is never the sole means of conveying type — icons are always present alongside color
Styling & Customization
All styles are scoped inside the component and applied via CSS classes. You can override them in your global styles.css:
/* Change position — top-right instead of bottom-right */
ng-toast-container .ng-toast-container {
bottom: auto;
top: 1.5rem;
}
/* Make toasts wider */
ng-toast-container .ng-toast-container {
max-width: 480px;
}
/* Custom success color */
ng-toast-container .ng-toast--success {
border-color: #0d9488;
}
/* Larger font */
ng-toast-container .ng-toast {
font-size: 1rem;
}CSS class reference
| Class | Element |
|---|---|
| .ng-toast-container | The outer wrapper (fixed position) |
| .ng-toast | Individual toast card |
| .ng-toast--success | Applied when type is success |
| .ng-toast--error | Applied when type is error |
| .ng-toast--warning | Applied when type is warning |
| .ng-toast--info | Applied when type is info |
| .ng-toast__icon | The emoji icon |
| .ng-toast__body | Wrapper for title + message |
| .ng-toast__title | The bold title text |
| .ng-toast__message | The main message text |
| .ng-toast__close | The × dismiss button |
| .ng-toast__progress | The animated progress bar |
FAQ
Q: Can I show a toast from a service (not a component)?
Yes. Just inject ToastService into any Angular class — component, service, guard, interceptor, or resolver.
Q: What happens if I call forRoot() in a lazy-loaded module?
A second instance of ToastService is created, meaning toasts shown from that module won't appear in the container. Always call forRoot() only in AppModule.
Q: Can I show multiple toasts at the same time?
Yes. Each call to success(), error(), etc. adds a new toast to the stack. They all display simultaneously and dismiss independently.
Q: How do I make a toast stay forever until the user closes it?
Pass duration: 0:
this.toast.warning('Please review before submitting.', { duration: 0 });Q: Can I use this with server-side rendering (SSR / Angular Universal)?
The library uses setTimeout and DOM-dependent styles which are browser-only. Wrap toast calls in a platform check to avoid SSR issues:
import { isPlatformBrowser } from '@angular/common';
import { PLATFORM_ID, inject } from '@angular/core';
const platformId = inject(PLATFORM_ID);
if (isPlatformBrowser(platformId)) {
this.toast.success('Loaded!');
}Q: Can I change the position of the toasts?
Yes, override the .ng-toast-container CSS class in your global stylesheet. See the Styling section above.
Changelog
1.0.0 — Initial release
ToastServicewithsuccess,error,warning,info,dismiss,clearToastContainerComponentwith progress bar and slide animationNgToastAlertsModulewithforRoot()pattern- Standalone app support
- Full accessibility support
Contributing
Contributions, issues, and feature requests are welcome.
- Fork the repository
- Create a branch:
git checkout -b feat/my-feature - Commit your changes:
git commit -m "feat: add my feature" - Push to the branch:
git push origin feat/my-feature - Open a Pull Request
License
MIT © saurabhkumar yadav
