@ngneat/hot-toast and ngx-toastr are both popular libraries for displaying non-blocking notification popups in Angular applications. ngx-toastr is the legacy standard, known for its stability and extensive configuration options built around Angular modules. @ngneat/hot-toast is a modern alternative inspired by React's hot-toast, designed for standalone components, functional providers, and a simpler API surface. Both handle success, error, warning, and info states, but they differ significantly in setup, customization, and alignment with recent Angular versions.
Both @ngneat/hot-toast and ngx-toastr solve the same problem — showing temporary feedback messages to users without blocking their workflow. However, they reflect different eras of Angular development. ngx-toastr represents the classic Module-based approach, while @ngneat/hot-toast embraces the modern Standalone and Functional API style. Let's compare how they handle setup, usage, and customization.
@ngneat/hot-toast uses functional providers, which fits cleanly into modern app.config.ts files.
provideHotToastConfig().// app.config.ts
import { provideHotToastConfig } from '@ngneat/hot-toast';
export const appConfig: ApplicationConfig = {
providers: [
provideHotToastConfig({
position: 'top-center',
duration: 3000
})
]
};
ngx-toastr relies on traditional NgModules and requires BrowserAnimationsModule.
ToastrModule.forRoot() in your app module.// app.module.ts
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ToastrModule } from 'ngx-toastr';
@NgModule({
imports: [
BrowserAnimationsModule,
ToastrModule.forRoot({
positionClass: 'toast-top-center',
timeOut: 3000
})
]
})
export class AppModule {}
@ngneat/hot-toast uses a simple service object imported directly.
toast.success() anywhere in your code.// component.ts
import { toast } from '@ngneat/hot-toast';
function saveData() {
toast.success('Data saved successfully');
// Or with options
toast.error('Failed to save', { duration: 5000 });
}
ngx-toastr requires injecting the ToastrService into your class.
// component.ts
import { ToastrService } from 'ngx-toastr';
@Component({ ... })
export class MyComponent {
constructor(private toastr: ToastrService) {}
saveData() {
this.toastr.success('Data saved successfully');
// Or with options
this.toastr.error('Failed to save', 'Error', { timeOut: 5000 });
}
}
@ngneat/hot-toast allows passing Angular components directly to the toast.
// component.ts
import { toast } from '@ngneat/hot-toast';
import { CustomComponent } from './custom.component';
function showCustom() {
toast.show(CustomComponent, {
data: { message: 'Action required' },
duration: 10000
});
}
ngx-toastr typically uses TemplateRef or ComponentPortal.
// component.ts
import { ToastrService } from 'ngx-toastr';
import { TemplateRef } from '@angular/core';
@Component({ ... })
export class MyComponent {
constructor(private toastr: ToastrService) {}
showCustom(templateRef: TemplateRef<any>) {
this.toastr.show(templateRef, 'Custom Title', {
toastClass: 'custom-toast'
});
}
}
@ngneat/hot-toast handles positioning via config objects.
style option.// component.ts
import { toast } from '@ngneat/hot-toast';
toast.success('Moved to bottom', {
position: 'bottom-center',
style: { background: 'blue', color: 'white' }
});
ngx-toastr uses CSS classes for positioning.
// component.ts
import { ToastrService } from 'ngx-toastr';
this.toastr.success('Moved to bottom', '', {
positionClass: 'toast-bottom-center',
toastClass: 'blue-theme'
});
@ngneat/hot-toast has built-in loading state management.
// component.ts
import { toast } from '@ngneat/hot-toast';
async function loadData() {
const loadingId = toast.load('Loading data...');
try {
await api.fetch();
toast.success('Done', { id: loadingId });
} catch {
toast.error('Failed', { id: loadingId });
}
}
ngx-toastr does not have built-in loading state transitions.
// component.ts
import { ToastrService } from 'ngx-toastr';
async function loadData() {
const loading = this.toastr.info('Loading data...');
try {
await api.fetch();
this.toastr.remove(loading.toastId);
this.toastr.success('Done');
} catch {
this.toastr.remove(loading.toastId);
this.toastr.error('Failed');
}
}
While the implementation differs, both libraries share core goals and capabilities.
// @ngneat/hot-toast
toast.success('OK');
toast.error('Fail');
// ngx-toastr
this.toastr.success('OK');
this.toastr.error('Fail');
// @ngneat/hot-toast
toast.show('Message', { duration: 4000 });
// ngx-toastr
this.toastr.show('Message', '', { timeOut: 4000 });
// @ngneat/hot-toast
toast.error('Critical', { duration: 0 });
// ngx-toastr
this.toastr.error('Critical', '', { disableTimeOut: true });
// Both handle this internally via role="alert"
// No extra code needed for basic support
| Feature | @ngneat/hot-toast | ngx-toastr |
|---|---|---|
| Setup | 🚀 Functional providers | 🧩 NgModules |
| Usage | 📦 Imported service object | 💉 Injected service |
| Custom UI | 🎨 Pass Component class | 🖼️ TemplateRef or Portal |
| Loading State | ✅ Built-in resolve/update | ❌ Manual remove/show |
| Styling | 🖌️ Inline style options | 🎭 CSS Classes |
| Modern Angular | ✅ Standalone ready | ⚠️ Requires adaptation |
@ngneat/hot-toast is like a modern utility belt 🎒 — lightweight, easy to grab, and designed for speed. It removes boilerplate and fits naturally into new Angular projects. Choose this for greenfield development where you want less configuration and more code.
ngx-toastr is like a heavy-duty toolbox 🧰 — robust, familiar, and everywhere. It has been around for years and works reliably in complex enterprise apps. Choose this for maintaining existing systems or if your team prefers traditional dependency injection patterns.
Final Thought: Both libraries will get the job done, but @ngneat/hot-toast reduces friction for modern Angular developers. If you are starting fresh, the simpler API and standalone support make it the logical choice — unless you are already locked into the ngx-toastr ecosystem.
Choose @ngneat/hot-toast if you are building a new Angular application using standalone components or recent versions (15+). It offers a simpler, function-based API that aligns with modern Angular practices like functional providers and signals. It is ideal for teams wanting less boilerplate and easier custom component integration without dealing with complex module imports.
Choose ngx-toastr if you are maintaining a legacy Angular application or need a battle-tested solution with a massive existing ecosystem. It is suitable for projects already using NgModules where migrating to a new notification system introduces unnecessary risk. It remains a solid choice for stable, long-term projects that do not require the latest Angular features.
Smoking hot Notifications for Angular. Lightweight, customizable and beautiful by default. Inspired from react-hot-toast
| @ngneat/hot-toast | Angular |
|---|---|
| 3.x | >= 9.1.13 < 13 |
| 4.x | >= 13 < 15 |
| 5.x | >= 15 < 16 |
| 6.x | >= 16 |
You can install it through Angular CLI:
ng add @ngneat/hot-toast
or with npm:
# For Angular version >= 9.1.13 < 13
npm install @ngneat/overview@2.0.2 @ngneat/hot-toast@3
# For Angular version >= 13 < 15
npm install @ngneat/overview@3.0.0 @ngneat/hot-toast@4
# For Angular version >= 15 <16
npm install @ngneat/overview@3.0.0 @ngneat/hot-toast@5
# For Angular version >= 16 <17
npm install @ngneat/overview@5.1.1 @ngneat/hot-toast@6
# For Angular version >= 17
npm install @ngneat/overview@6.0.0 @ngneat/hot-toast@7
This is taken care with ng add @ngneat/hot-toast
Now HotToastModule in your app.module. You can also set global toast options (Partial<ToastConfig>) here.:
import { HotToastModule } from '@ngneat/hot-toast';
@NgModule({
imports: [HotToastModule.forRoot()],
})
class AppModule {}
import { AppComponent } from './src/app.component';
import { provideHotToastConfig } from '@ngneat/hot-toast';
bootstrapApplication(AppComponent, {
providers: [
provideHotToastConfig(), // @ngneat/hot-toast providers
]
});
if you use SCSS add this line to your main styles.scss:
@use '@ngneat/hot-toast/src/styles/styles.scss';
or if you use CSS add this to your styles inside your angular.json:
"styles": [
"node_modules/@ngneat/hot-toast/src/styles/styles.css",
],
import { HotToastService } from '@ngneat/hot-toast';
@Component({})
export class AppComponent {
constructor(private toast: HotToastService) {}
showToast() {
this.toast.show('Hello World!');
this.toast.loading('Lazyyy...');
this.toast.success('Yeah!!');
this.toast.warning('Boo!');
this.toast.error('Oh no!');
this.toast.info('Something...');
}
update() {
saveSettings
.pipe(
this.toast.observe({
loading: 'Saving...',
success: 'Settings saved!',
error: 'Could not save.',
})
)
.subscribe();
}
}
You can pass ToastOptions while creating the toast to customize the look and behavior:
import { HotToastService } from '@ngneat/hot-toast';
@Component({})
export class AppComponent {
constructor(private toast: HotToastService) {}
customToast() {
this.toast.success('Look at my styles, and I also need more time!', {
duration: 5000,
style: {
border: '1px solid #713200',
padding: '16px',
color: '#713200',
},
iconTheme: {
primary: '#713200',
secondary: '#FFFAEE',
},
});
}
}
You can also set global ToastConfig options while importing:
import { HotToastModule } from '@ngneat/hot-toast';
@NgModule({
imports: [
HotToastModule.forRoot({
reverseOrder: true,
dismissible: true,
autoClose: false,
}),
],
})
class AppModule {}
Additionally, you have the option of using a standalone function to provide a global toast configuration within your app's configuration file:
// app.config.ts
import { provideHotToastConfig } from '@ngneat/hot-toast';
export const appConfig: ApplicationConfig = {
providers: [provideHotToastConfig({ ... })],
};
You can checkout examples at: https://ngneat.github.io/hot-toast#examples.
All options, which are set Available in global config? from ToastOptions are supported. Below are extra configurable options:
| Name | Type | Description |
|---|---|---|
| reverseOrder | boolean | Sets the reverse order for hot-toast stacking Default: false |
| visibleToasts | number | Sets the number of toasts visible. 0 will set no limit. Default: 5 |
| stacking | "vertical"|"depth" | Sets Sets the type of stacking Default: "vertical" |
Configuration used when opening an hot-toast.
| Name | Type | Description | Available in global config? |
|---|---|---|---|
| id | string | Unique id to associate with hot-toast. There can't be multiple hot-toasts opened with same id. Example | No |
| duration | number | Duration in milliseconds after which hot-toast will be auto closed. Can be disabled via autoClose: falseDefault: 3000, error = 4000, loading = 30000 | Yes |
| autoClose | boolean | Auto close hot-toast after duration Default: true | Yes |
| position | ToastPosition | The position to place the hot-toast. Default: top-centerExample | Yes |
| dismissible | boolean | Show close button in hot-toast Default: falseExample | Yes |
| role | ToastRole | Role of the live region. Default: status | Yes |
| ariaLive | ToastAriaLive | aria-live value for the live region. Default: polite | Yes |
| theme | ToastTheme | Visual appearance of hot-toast Default: toastExample | Yes |
| persist | {ToastPersistConfig} | Useful when you want to keep a persistance for toast based on ids, across sessions. Example | No |
| icon | Content | Icon to show in the hot-toast Example | Yes |
| iconTheme | IconTheme | Use this to change icon color Example | Yes |
| className | string | Extra CSS classes to be added to the hot toast container. | Yes |
| attributes | Record<string, string> | Extra attributes to be added to the hot toast container. Can be used for e2e tests. | Yes |
| style | style object | Extra styles to apply for hot-toast. Example | Yes |
| closeStyle | style object | Extra styles to apply for close button | Yes |
| data | DataType | Allows you to pass data for your template and component. You can access the data using toastRef.data.Examples: Template with Data, Component with Data | No |
| injector | Injector | Allows you to pass injector for your component. Example | No |
Latest versions of Chrome, Edge, Firefox and Safari are supported, with some known issues.
Hot-toast messages are announced via an aria-live region. By default, the polite setting is used. While polite is recommended, this can be customized by setting the ariaLive property of the ToastConfig or ToastOptions.
Focus is not, and should not be, moved to the hot-toast element. Moving the focus would be disruptive to a user in the middle of a workflow. It is recommended that, for any action offered in the hot-toast, the application offers the user an alternative way to perform the action. Alternative interactions are typically keyboard shortcuts or menu options. When the action is performed in this way, the hot-toast should be dismissed.
Hot-toasts that have an action available should be set autoClose: false, as to accommodate screen-reader users that want to navigate to the hot-toast element to activate the action.
.hot-toast-message were wrapped into dynamic-content, now they are wrapped into div > dynamic-viewtoastRef in template. E.g. toastRef?.data@Optional() decorator in components' constructor while injecting tokens which are used by toast's injectorFor this version you will also need to import the styles from the library like this if you're not using NgAdd
if you use SCSS add this line to your main styles.scss:
@use 'node_modules/@ngneat/hot-toast/src/styles/styles.scss';
or if you use CSS add this to your styles inside your angular.json:
"styles": [
"node_modules/@ngneat/hot-toast/src/styles/styles.css",
],
Thanks goes to these wonderful people (emoji key):
Dharmen Shah 💻 🖋 🎨 📖 💡 | Netanel Basal 🐛 💼 🤔 🚧 🧑🏫 📆 🔬 👀 | Timo Lins 🎨 🤔 | Patrick Miller 🚧 📦 | Gili Yaniv 💻 | Artur Androsovych 🚧 | Luis Castro 💻 |
This project follows the all-contributors specification. Contributions of any kind welcome!