π» Code samples Drop-in API
Bundler (TS)
CDN (HTML)
React
Basic API
Options
Promise API
Migration
// 1. Install
npm install toastr-next
// 2. src/main.ts β entry file (same code works under Vite, Webpack,
// Rollup, Parcel, esbuild. No special bundler config needed.)
import { toastr } from 'toastr-next';
// CSS is auto-injected on first import β no `import 'toastr-next/style'`.
toastr.options = {
positionClass: 'toast-top-right',
progressBar: true,
closeButton: true,
timeOut: 4000,
};
document.getElementById('save')!.addEventListener('click', async () => {
const t = toastr.info('Savingβ¦', '', { timeOut: 0 });
try {
await saveToServer();
t.clear();
await t.dismissed;
toastr.success('Saved!');
} catch {
t.clear();
toastr.error('Save failed');
}
});
// 3. index.html (Vite-style)
// <button id="save">Save</button>
// <script type="module" src="/src/main.ts"></script>
<!-- One self-contained HTML file. No npm, no bundler, no build. -->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>toastr-next CDN demo</title>
</head>
<body>
<button id="ok">Show success</button>
<button id="err">Show error</button>
<!-- Loads window.toastr and auto-injects CSS -->
<script src="https://cdn.jsdelivr.net/npm/toastr-next@3/dist/toastr-next.iife.js"></script>
<script>
toastr.options = {
positionClass: 'toast-top-right',
progressBar: true,
closeButton: true,
};
document.getElementById('ok').addEventListener('click', () => {
toastr.success('Saved!', 'Success');
});
document.getElementById('err').addEventListener('click', () => {
toastr.error('Something went wrong', 'Error');
});
</script>
</body>
</html>
// Pin a version: @3.0.7 for exact, @3 for latest 3.x.
// unpkg also works: https://unpkg.com/toastr-next@3/dist/toastr-next.iife.js
// 1. Install β React 17+ is required as a peer dependency
npm install toastr-next
// 2. src/App.tsx β mount the Provider once near the root.
// <ToastrProvider /> is self-closing and renders null.
import { ToastrProvider } from 'toastr-next/react';
import { SaveButton } from './SaveButton';
export default function App() {
return (
<>
<ToastrProvider
position="toast-top-right"
options={{ progressBar: true, closeButton: true }}
/>
<SaveButton />
</>
);
}
// 3. src/SaveButton.tsx β trigger toasts via the hook
import { useToastr } from 'toastr-next/react';
export function SaveButton() {
const toast = useToastr();
return (
<button onClick={async () => {
const t = toast.info('Savingβ¦', '', { timeOut: 0 });
await saveToServer();
t.clear();
await t.dismissed;
toast.success('Saved!');
}}>Save</button>
);
}
// SSR note: import is safe on the server, but calling toast.*() from a
// server component throws (it uses document.createElement). Trigger
// toasts from client components / "use client" boundaries only.
// Four notification types β (message, title?, options?)
toastr.success('Saved!');
toastr.error('Failed', 'Oops');
toastr.info('New update');
toastr.warning('Low disk space', 'Warning');
// Global defaults β assigning REPLACES the whole object (not merged)
toastr.options = {
positionClass: 'toast-bottom-right',
animation: 'bounce',
progressBar: true,
closeButton: true,
};
// Per-call options override globals
toastr.success('Done!', '', { animation: 'flip', timeOut: 3000 });
// Sticky toast β timeOut + extendedTimeOut both 0
toastr.warning('Confirm to proceed', 'Action required', {
timeOut: 0,
extendedTimeOut: 0,
closeButton: true,
});
// Dismiss all toasts
toastr.clear(); // animate out
toastr.remove(); // remove immediately
// Every option below is optional. Defaults shown.
// Set on toastr.options globally, or pass per-call as the 3rd arg.
toastr.options = {
// βββ Timing ββββββββββββββββββββββββββββββββββββββββββββββ
timeOut: 5000, // ms before auto-dismiss; 0 = sticky
extendedTimeOut: 1000, // ms to keep open after the pointer leaves
// βββ Position & layout ββββββββββββββββββββββββββββββββββ
positionClass: 'toast-top-right', // see list at bottom
newestOnTop: true, // stack newest on top of the pile
target: 'body', // CSS selector for the container parent
rtl: false, // right-to-left layout (icon flips to right)
// βββ Animation βββββββββββββββββββββββββββββββββββββββββββ
animation: 'fade', // 'fade' | 'slide' | 'bounce' | 'flip'
// βββ Interaction βββββββββββββββββββββββββββββββββββββββββ
tapToDismiss: true, // click the toast body to dismiss
closeOnHover: true, // pause the countdown while hovering
closeButton: false, // show the Γ close button
closeHtml: '<button type="button" aria-label="Close notification">Γ</button>',
// βββ Visual ββββββββββββββββββββββββββββββββββββββββββββββ
progressBar: false, // show countdown progress bar at the bottom
// βββ Behavior ββββββββββββββββββββββββββββββββββββββββββββ
preventDuplicates: false, // suppress identical messages already on screen
allowHtml: false, // render HTML in message/title (escaped by default β XSS-safe)
// βββ Lifecycle callbacks (all optional) ββββββββββββββββββ
onShown: () => {}, // fired after the enter animation completes
onHidden: () => {}, // fired after the hide animation completes
onclick: (e) => {}, // fired when the toast body is clicked
onCloseClick: (e) => {}, // fired when the Γ button is clicked
};
// βββ All eight position classes ββββββββββββββββββββββββββββ
// 'toast-top-right' 'toast-top-left' 'toast-top-center' 'toast-top-full-width'
// 'toast-bottom-right' 'toast-bottom-left' 'toast-bottom-center' 'toast-bottom-full-width'
// βββ Per-call override (only this toast gets the override) β
toastr.success('Done!', 'Saved', {
animation: 'bounce',
positionClass: 'toast-bottom-right',
timeOut: 3000,
onclick: (e) => console.log('clicked', e),
});
// βββ Mutate a single key (does not replace the whole object) β
toastr.options.timeOut = 3000;
// Every toastr.*() call returns a ToastInstance synchronously
const toast = toastr.success('Changes saved!');
// dismissed resolves after the hide animation finishes
await toast.dismissed;
window.location.assign('/dashboard');
// Programmatic dismissal during async work
const t = toastr.info('Uploadingβ¦', '', { timeOut: 0, closeButton: true });
await uploadFile();
t.clear(); // trigger dismiss animation
await t.dismissed; // wait until it's fully gone
toastr.success('Upload complete!');
// Subscribe to all lifecycle events; returns an unsubscribe fn
const unsub = toastr.subscribe((e) => {
// e.state: "shown" | "hidden" | "clicked"
// e.type: "success" | "error" | "info" | "warning"
console.log(e.type, e.state, e.message);
});
unsub();
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// MIGRATION GUIDE β toastr 2.x β toastr-next 3.x
// Seven concrete steps. Most apps need only steps 1β3.
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// βββ 1. Remove jQuery βββββββββββββββββββββββββββββββββββββ
// OLD
// <script src="jquery.min.js"></script>
// <script src="toastr.min.js"></script>
// NEW β zero runtime deps
npm uninstall jquery toastr
npm install toastr-next
// βββ 2. Update imports ββββββββββββββββββββββββββββββββββββ
// OLD
// import toastr from 'toastr';
// import 'toastr/build/toastr.min.css';
// NEW β CSS is auto-injected on first import
import { toastr } from 'toastr-next';
// βββ 3. Replace animation options βββββββββββββββββββββββββ
// OLD β six jQuery-easing options
// toastr.options.showMethod = 'slideDown';
// toastr.options.hideMethod = 'slideUp';
// toastr.options.showEasing = 'easeOutBounce';
// toastr.options.hideEasing = 'easeInBack';
// NEW β one option, four CSS presets
toastr.options.animation = 'slide'; // 'fade' | 'slide' | 'bounce' | 'flip'
// REMOVED entirely (no replacement needed β handled by the presets):
// showMethod, hideMethod, closeMethod, showEasing, hideEasing, closeEasing
// βββ 4. Update the subscribe() callback βββββββββββββββββββ
// OLD β returned void
// toastr.subscribe(callback);
// NEW β returns an unsubscribe function
const unsubscribe = toastr.subscribe(callback);
// laterβ¦
unsubscribe();
// βββ 5. Handle the new return type ββββββββββββββββββββββββ
// OLD β returned a jQuery object
// const $toast = toastr.success('Saved!');
// $toast.css('color', 'red');
// NEW β returns a typed ToastInstance
const instance = toastr.success('Saved!');
await instance.dismissed; // resolves when the toast is gone
instance.clear(); // trigger dismiss animation
instance.remove(); // remove immediately, no animation
// βββ 6. New β instance.dismissed Promise ββββββββββββββββββ
const t = toastr.warning('Are you sure?', '', {
timeOut: 0,
closeButton: true,
});
await t.dismissed;
proceed();
// βββ 7. Replace escapeHtml with allowHtml βββββββββββββββββ
// HTML is now ESCAPED BY DEFAULT (secure). To opt in, pass allowHtml.
// OLD β escaping was off by default, escapeHtml turned it on
// toastr.success('<b>Bold</b>', '', { escapeHtml: false });
// NEW β explicit opt-in
toastr.success('<b>Bold</b>', '', { allowHtml: true });
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Cheatsheet β preserved vs changed vs removed
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// PRESERVED toastr.{success,error,info,warning}(msg, title?, opts?)
// toastr.options, toastr.clear(), toastr.remove(),
// positionClass, timeOut, extendedTimeOut, closeButton,
// progressBar, newestOnTop, preventDuplicates, tapToDismiss,
// closeOnHover, rtl, target, closeHtml,
// onShown, onHidden, onclick, onCloseClick
//
// CHANGED subscribe(cb) β now returns unsubscribe fn
// success(...) β ToastInstance (was jQuery object)
// escapeHtml: false β allowHtml: true (inverted)
//
// REMOVED showMethod, hideMethod, closeMethod
// showEasing, hideEasing, closeEasing
// (use `animation` preset instead)
//
// NEW animation: 'fade'|'slide'|'bounce'|'flip'
// instance.dismissed Promise
// instance.clear() / instance.remove()
// allowHtml (escaped-by-default content)
// React adapter: import { ToastrProvider, useToastr }
// from 'toastr-next/react'