angular-notifier and ngx-toastr are both popular libraries for displaying non-blocking notification messages (toasts) in Angular applications. angular-notifier is a modern, highly customizable library built specifically for Angular, offering extensive configuration options, multiple notification types, and a clean API that integrates well with Angular's dependency injection system. ngx-toastr is the Angular port of the widely-used toastr library, known for its simplicity, lightweight footprint, and familiar API for developers migrating from jQuery-based projects. Both libraries support standard notification types (success, error, warning, info) and provide mechanisms for programmatic control, but they differ significantly in architecture, customization capabilities, and maintenance status.
When building professional Angular applications, displaying timely feedback to users through toast notifications is a common requirement. Two prominent solutions exist: angular-notifier and ngx-toastr. While both serve the same fundamental purpose, they differ significantly in architecture, customization capabilities, and long-term viability. Let's examine how they handle real-world scenarios.
angular-notifier follows a modern Angular pattern with dedicated services and configuration tokens.
// angular-notifier: Module setup
import { NotifierModule, NotifierOptions } from 'angular-notifier';
const customNotifierOptions: NotifierOptions = {
behaviour: {
autoHide: 5000,
onClick: 'hide'
},
position: {
horizontal: { position: 'right', distance: 12 },
vertical: { position: 'top', distance: 12, gap: 10 }
}
};
@NgModule({
imports: [
NotifierModule.withConfig(customNotifierOptions)
]
})
export class AppModule {}
ngx-toastr uses a simpler, more direct approach reminiscent of the original toastr library.
// ngx-toastr: Module setup
import { ToastrModule } from 'ngx-toastr';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
imports: [
BrowserAnimationsModule,
ToastrModule.forRoot({
timeOut: 5000,
positionClass: 'toast-top-right',
preventDuplicates: true
})
]
})
export class AppModule {}
angular-notifier provides extensive theming capabilities through CSS variables and template customization.
// angular-notifier: Custom notification with template
this.notifierService.notify('custom', {
title: 'Custom Alert',
message: 'This uses a custom template',
html: '<strong>Bold content</strong> with <em>emphasis</em>'
});
// In component template
<notifier-notification>
<ng-template notifierNotificationTemplate let-notification>
<div class="custom-toast">
<h3>{{ notification.title }}</h3>
<p>{{ notification.message }}</p>
</div>
</ng-template>
</notifier-notification>
ngx-toastr offers basic customization through configuration options but lacks template flexibility.
// ngx-toastr: Basic customization
this.toastr.success('Operation completed', 'Success', {
timeOut: 3000,
easing: 'ease-in',
easeTime: 300
});
// CSS override required for custom styling
/* .toast-success { background-color: #custom-color !important; } */
angular-notifier gives developers fine-grained control over individual notifications.
// angular-notifier: Lifecycle control
const notificationId = this.notifierService.notify('success', 'Processing...');
// Hide specific notification later
this.notifierService.hide(notificationId);
// Subscribe to hide events
this.notifierService.onHide().subscribe((id) => {
console.log(`Notification ${id} was hidden`);
});
ngx-toastr provides simpler control mechanisms with less granularity.
// ngx-toastr: Basic control
const toastRef = this.toastr.success('Task started');
// Hide specific toast
toastRef.onHidden.subscribe(() => {
console.log('Toast was hidden');
});
// Clear all toasts
this.toastr.clear();
angular-notifier supports sophisticated positioning with gap management and responsive behavior.
// angular-notifier: Advanced positioning
const config: NotifierOptions = {
position: {
horizontal: { position: 'left', distance: 20 },
vertical: { position: 'bottom', distance: 20, gap: 15 }
}
};
ngx-toastr uses predefined position classes with limited flexibility.
// ngx-toastr: Predefined positions
this.toastr.error('Something went wrong', 'Error', {
positionClass: 'toast-bottom-left'
});
angular-notifier shows active maintenance with regular updates aligned to Angular versions.
ngx-toastr has exhibited reduced maintenance activity in recent periods.
You need rich notifications with custom templates, progress indicators, and action buttons.
angular-notifier// angular-notifier: Complex notification
this.notifierService.notify('info', {
title: 'Data Export',
message: 'Your report is being generated',
html: `
<div class="progress-container">
<progress value="70" max="100"></progress>
<button (click="cancelExport()">Cancel</button>
</div>
`
});
You need quick success/error messages with minimal setup effort.
ngx-toastr// ngx-toastr: Simple feedback
this.toastr.success('Record saved successfully');
this.toastr.error('Failed to connect to server');
Your application requires notifications that adapt to different languages and contexts.
angular-notifier// angular-notifier: Dynamic content
this.notifierService.notify('warning', {
title: this.translateService.instant('WARNING'),
message: this.translateService.instant('SESSION_EXPIRING'),
html: `<button>${this.translateService.instant('RENEW')}</button>`
});
| Feature | angular-notifier | ngx-toastr |
|---|---|---|
| Setup Complexity | 🧩 Moderate (configuration tokens) | ✅ Simple (direct service) |
| Custom Templates | ✅ Full HTML template support | ❌ Limited to text content |
| Position Control | 🎯 Granular (gap, distance, responsive) | 📍 Predefined classes only |
| Lifecycle Hooks | 🔄 Rich observables for events | ⚡ Basic onHidden/onShown |
| TypeScript Support | 💪 Excellent (modern types) | 👍 Good (established types) |
| Maintenance Status | 🟢 Active development | 🟡 Reduced recent activity |
| Bundle Size | 📦 Moderate | 📦 Lightweight |
Choose angular-notifier when:
Choose ngx-toastr when:
For new projects starting today, angular-notifier presents a more sustainable choice due to its active maintenance cycle and alignment with modern Angular practices. Its architecture supports evolving requirements like custom templates, advanced positioning, and comprehensive lifecycle management – features increasingly expected in professional applications.
While ngx-toastr remains functional for basic use cases, teams should weigh the risks of potential compatibility issues with future Angular versions against the benefits of its simplicity. Consider prototyping with both libraries to evaluate which better fits your specific workflow before making a final architectural decision.
Both libraries solve the core problem effectively, but the choice ultimately depends on your project's complexity, timeline, and long-term maintenance strategy.
Choose angular-notifier if you need a modern, actively maintained notification system with deep customization options, strong TypeScript support, and flexible positioning controls. It is ideal for new Angular projects where you require fine-grained control over notification behavior, styling, and lifecycle management. The library's architecture aligns well with current Angular best practices, making it suitable for enterprise applications that demand robustness and extensibility.
Choose ngx-toastr if you prioritize simplicity, minimal setup, and familiarity with the classic toastr API. It works well for smaller projects or teams migrating from legacy jQuery-based applications where consistency with existing patterns matters. However, be aware that this package has shown signs of reduced maintenance activity in recent years, so evaluate long-term support needs carefully before adopting it for critical production systems.
A well designed, fully animated, highly customizable, and easy-to-use notification library for your Angular 2+ application.
You can play around with this library with this Stackblitz right here.

You can get angular-notifier via npm by either adding it as a new dependency to your package.json file and running npm install,
or running the following command:
npm install angular-notifier
The following list describes the compatibility with Angular:
| Angular Notifier | Angular | Compilation |
|---|---|---|
1.x | 2.x | View Engine |
2.x | 4.x | View Engine |
3.x | 5.x | View Engine |
4.x | 6.x | View Engine |
5.x | 7.x | View Engine |
6.x | 8.x | View Engine |
7.x | 9.x | View Engine |
8.x | 10.x | View Engine |
9.x | 11.x | View Engine |
10.x | 12.x | View Engine |
11.x | 13.x | Ivy (partial mode) |
12.x | 14.x | Ivy (partial mode) |
13.x | 15.x | Ivy (partial mode) |
14.x | 16.x | Ivy (partial mode) |
Before actually being able to use the angular-notifier library within our code, we have to first set it up within Angular, and also bring the styles into our project.
NotifierModuleFirst of all, make angular-notifier globally available to your Angular application by importing (and optionally also configuring) the
NotifierModule the your root Angular module. For example:
import { NotifierModule } from 'angular-notifier';
@NgModule({
imports: [NotifierModule],
})
export class AppModule {}
But wait -- your probably might want to customize your notifications' look and behaviour according to your requirements and needs. To do so,
call the withConfig method on the NotifierModule, and pass in the options. For example:
import { NotifierModule } from 'angular-notifier';
@NgModule({
imports: [
NotifierModule.withConfig({
// Custom options in here
}),
],
})
export class AppModule {}
notifier-container componentIn addition, you have to place the notifier-container component somewhere in your application, best at the last element of your
root (app) component. For example:
@Component({
selector: 'my-app',
template: `
<h1>Hello World</h1>
<notifier-container></notifier-container>
`,
})
export class AppComponent {}
Later on, this component will contain and manage all your applications' notifications.
Of course we also need to import the angular-notifier styles into our application. Depending on the architecture of your Angular application, you want to either import the original SASS files, or the already compiled CSS files instead - or none of them if you wish to write your own styles from scratch.
To import all the styles, simple include either the ~/angular-notifier/styles.(scss|css) file. It contains the core styles as well as all
the themes and notification types.
To keep the size if your styles as small as possible (improving performance for the perfect UX), your might instead decide to only import the styles actually needed by our application. The angular-notifier styles are modular:
~/angular-notifier/styles/core.(scss|css) file is always required, it defines the basic styles (such as the layout)~/angular-notifier/styles/theme folder~/angular-notifier/styles/types folderUsing angular-notifier is as simple as it can get -- simple import and inject the NotifierService into every component (directive,
service, ...) you want to use in. For example:
import { NotifierService } from 'angular-notifier';
@Component({
// ...
})
export class MyAwesomeComponent {
private readonly notifier: NotifierService;
constructor(notifierService: NotifierService) {
this.notifier = notifierService;
}
}
Showing a notification is simple - all your need is a type, and a message to be displayed. For example:
this.notifier.notify('success', 'You are awesome! I mean it!');
You can further pass in a notification ID as the third (optional) argument. Essentially, such a notification ID is nothing more but a unique string tha can be used later on to gain access (and thus control) to this specific notification. For example:
this.notifier.notify('success', 'You are awesome! I mean it!', 'THAT_NOTIFICATION_ID');
For example, you might want to define a notification ID if you know that, at some point in the future, you will need to remove this exact notification.
The syntax above is actually just a shorthand version of the following:
this.notifier.show({
type: 'success',
message: 'You are awesome! I mean it!',
id: 'THAT_NOTIFICATION_ID', // Again, this is optional
});
You can also hide notifications. To hide a specific notification - assuming you've defined a notification ID when creating it, simply call:
this.notifier.hide('THAT_NOTIFICATION_ID');
Furthermore, your can hide the newest notification by calling:
this.notifier.hideNewest();
Or, your could hide the oldest notification:
this.notifier.hideOldest();
And, of course, it's also possible to hide all visible notifications at once:
this.notifier.hideAll();
From the beginning, the angular-notifier library has been written with customizability in mind. The idea is that angular-notifier works the way your want it to, so that you can make it blend perfectly into the rest of your application. Still, the default configuration should already provide a great User Experience.
Keep in mind that angular-notifier can be configured only once - which is at the time you import the
NotifierModuleinto your root (app) module.
With the position property you can define where exactly notifications will appear on the screen:
position: {
horizontal: {
/**
* Defines the horizontal position on the screen
* @type {'left' | 'middle' | 'right'}
*/
position: 'left',
/**
* Defines the horizontal distance to the screen edge (in px)
* @type {number}
*/
distance: 12
},
vertical: {
/**
* Defines the vertical position on the screen
* @type {'top' | 'bottom'}
*/
position: 'bottom',
/**
* Defines the vertical distance to the screen edge (in px)
* @type {number}
*/
distance: 12
/**
* Defines the vertical gap, existing between multiple notifications (in px)
* @type {number}
*/
gap: 10
}
}
With the theme property you can change the overall look and feel of your notifications:
/**
* Defines the notification theme, responsible for the Visual Design of notifications
* @type {string}
*/
theme: 'material';
Well, how does theming actually work? In the end, the value set for the theme property will be part of a class added to each notification
when being created. For example, using material as the theme results in all notifications getting a class assigned named x-notifier__notification--material.
Everyone - yes, I'm looking at you - can use this mechanism to write custom notification themes and apply them via the
themeproperty. For example on how to create a theme from scratch, just take a look at the themes coming along with this library (as for now only thematerialtheme).
With the behaviour property you can define how notifications will behave in different situations:
behaviour: {
/**
* Defines whether each notification will hide itself automatically after a timeout passes
* @type {number | false}
*/
autoHide: 5000,
/**
* Defines what happens when someone clicks on a notification
* @type {'hide' | false}
*/
onClick: false,
/**
* Defines what happens when someone hovers over a notification
* @type {'pauseAutoHide' | 'resetAutoHide' | false}
*/
onMouseover: 'pauseAutoHide',
/**
* Defines whether the dismiss button is visible or not
* @type {boolean}
*/
showDismissButton: true,
/**
* Defines whether multiple notification will be stacked, and how high the stack limit is
* @type {number | false}
*/
stacking: 4
}
If you need more control over how the inner HTML part of the notification looks like, either because your style-guide requires it, or for being able to add icons etc, then you can define a custom <ng-template> which you pass to the NotifierService.
You can define a custom ng-template as follows:
<ng-template #customNotification let-notificationData="notification">
<my-custom-alert type="notificationData.type"> {{ notificationData.message }} </my-custom-alert>
</ng-template>
In this case you could wrap your own HTML, even a <my-custom-alert> component which you might use in your application. The notification data is passed in as a notification object, which you can reference inside the <ng-template> using the let- syntax.
Inside your component, you can then reference the <ng-template> by its template variable #customNotification using Angular's ViewChild:
import { ViewChild } from '@angular/core';
@Component({
// ...
})
export class SomeComponent {
@ViewChild('customNotification', { static: true }) customNotificationTmpl;
constructor(private notifierService: NotifierService) {}
showNotification() {
this.notifier.show({
message: 'Hi there!',
type: 'info',
template: this.customNotificationTmpl,
});
}
}
With the animations property your can define whether and how exactly notification will be animated:
animations: {
/**
* Defines whether all (!) animations are enabled or disabled
* @type {boolean}
*/
enabled: true,
show: {
/**
* Defines the animation preset that will be used to animate a new notification in
* @type {'fade' | 'slide'}
*/
preset: 'slide',
/**
* Defines how long it will take to animate a new notification in (in ms)
* @type {number}
*/
speed: 300,
/**
* Defines which easing method will be used when animating a new notification in
* @type {'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out'}
*/
easing: 'ease'
},
hide: {
/**
* Defines the animation preset that will be used to animate a new notification out
* @type {'fade' | 'slide'}
*/
preset: 'fade',
/**
* Defines how long it will take to animate a new notification out (in ms)
* @type {number}
*/
speed: 300,
/**
* Defines which easing method will be used when animating a new notification out
* @type {'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out'}
*/
easing: 'ease',
/**
* Defines the animation offset used when hiding multiple notifications at once (in ms)
* @type {number | false}
*/
offset: 50
},
shift: {
/**
* Defines how long it will take to shift a notification around (in ms)
* @type {number}
*/
speed: 300,
/**
* Defines which easing method will be used when shifting a notification around
* @type {string}
*/
easing: 'ease' // All standard CSS easing methods work
},
/**
* Defines the overall animation overlap, allowing for much smoother looking animations (in ms)
* @type {number | false}
*/
overlap: 150
}
To sum it up, the following is the default configuration (copy-paste-friendly):
const notifierDefaultOptions: NotifierOptions = {
position: {
horizontal: {
position: 'left',
distance: 12,
},
vertical: {
position: 'bottom',
distance: 12,
gap: 10,
},
},
theme: 'material',
behaviour: {
autoHide: 5000,
onClick: false,
onMouseover: 'pauseAutoHide',
showDismissButton: true,
stacking: 4,
},
animations: {
enabled: true,
show: {
preset: 'slide',
speed: 300,
easing: 'ease',
},
hide: {
preset: 'fade',
speed: 300,
easing: 'ease',
offset: 50,
},
shift: {
speed: 300,
easing: 'ease',
},
overlap: 150,
},
};