Documentation
Everything you need to get started with toast-23.
Getting Started
Install toast-23 and create your first toast in minutes.
Installation
Install toast-23 using your preferred package manager:
npm install toast-23yarn add toast-23pnpm add toast-23Quick Start
1Import the stylesheet
Import the toast-23 CSS in your app's entry point.
// main.tsx, layout.tsx, or _app.tsx
import "toast-23/styles.css";2Wrap your app with the provider
The Toast23Provider manages toast state and renders toast containers.
import { Toast23Provider } from "toast-23";
export default function App() {
return (
<Toast23Provider
position="top-right"
maxVisible={5}
duration={5000}
>
<YourApp />
</Toast23Provider>
);
}3Use the hook in any component
Call useToast() to get the toast API with variant shortcuts.
import { useToast } from "toast-23";
function MyComponent() {
const toast = useToast();
return (
<div>
<button onClick={() => toast("Hello world!")}>
Default
</button>
<button onClick={() => toast.success("Saved!")}>
Success
</button>
<button onClick={() => toast.error("Oops!")}>
Error
</button>
</div>
);
}Usage Guide
Learn how to use every feature of toast-23.
Variants
toast-23 includes 5 visual variants, each with distinct colors for both light and dark mode:
success
toast.success()
Completed actions, saved data
error
toast.error()
Failed operations, validation errors
warning
toast.warning()
Potential issues, important notices
info
toast.info()
General information, updates
default
toast()
Neutral messages
| Variant | Method | Use Case |
|---|---|---|
| success | toast.success() | Completed actions, saved data |
| error | toast.error() | Failed operations, validation errors |
| warning | toast.warning() | Potential issues, important notices |
| info | toast.info() | General information, updates |
| default | toast() | Neutral messages |
Loading Toast
Create a loading notification. Most likely, you'll want to update it afterwards. For a friendly alternative, check out toast.promise(), which takes care of that automatically.
const toast = useToast();
// Show loading toast
const toastId = toast.loading("Waiting...");
// Later, update it to success
toast.success("Done!", { id: toastId });Tip: Loading toasts are persistent by default (duration: 0) and non-dismissible. Update them with a new variant when your operation finishes.
Promise API
Track async operations with automatic state transitions. The toast updates automatically when the promise resolves or fails.
Simple Usage
const toast = useToast();
const myPromise = fetchData();
toast.promise(myPromise, {
loading: "Loading",
success: "Got the data",
error: "Error when fetching",
});Advanced
Provide a function to the success/error messages to incorporate the result/error. The third argument accepts toast options:
toast.promise(
myPromise,
{
loading: "Loading",
success: (data) => `Successfully saved ${data.name}`,
error: (err) => `This just happened: ${err.toString()}`,
},
{
duration: 5000,
position: "bottom-center",
}
);Using an Async Function
You can also provide a function that returns a promise, which will be called automatically:
toast.promise(
async () => {
const { id } = await fetchData1();
await fetchData2(id);
},
{
loading: "Loading",
success: "Got the data",
error: "Error when fetching",
}
);Tip: It's recommended to set a minWidth on your promise toasts to prevent layout jumps from different message lengths.
Custom (JSX)
Create a fully custom notification with JSX. Custom toasts render your content without any default styles.
toast.custom(<div>Hello World</div>);Render JSX with Default Styles
To render custom JSX content with the default toast styling, pass JSX directly to toast() instead:
toast(
<span>
Custom and <b>bold</b>
</span>,
{
title: "My Custom Toast",
}
);Dismiss from Custom Content
Use the returned toast id to add dismiss buttons inside your custom content:
const toastId = toast.custom(
<div className="my-custom-toast">
<p>Something happened</p>
<button onClick={() => toast.dismiss(toastId)}>
Dismiss
</button>
</div>
);Positioning
Set a default position on the provider, and optionally override per-toast:
// Default position for all toasts
<Toast23Provider position="bottom-right">
<App />
</Toast23Provider>
// Override position for a specific toast
toast.success("Saved!", { position: "top-left" });Click a position to preview a real toast notification:
Toast Options
Every toast method accepts an optional options object:
toast.success("Saved!", {
title: "Auto-save",
duration: 6000,
position: "bottom-right",
dismissible: true,
});
// Persistent toast (must be dismissed manually)
const id = toast.info("Processing...", { duration: 0 });
// Later, dismiss it
toast.dismiss(id);Default Durations
Every type has its own default duration. You can overwrite them with toast options per-toast or globally via the provider.
| Type | Duration |
|---|---|
| success | 5000ms (provider default) |
| error | 5000ms (provider default) |
| warning | 5000ms (provider default) |
| info | 5000ms (provider default) |
| default | 5000ms (provider default) |
| loading | Infinity (persistent) |
| custom | 5000ms (provider default) |
// Override provider default duration
<Toast23Provider duration={3000}>
<App />
</Toast23Provider>
// Override per-toast
toast.success("Quick!", { duration: 2000 });Dismiss & Remove
Programmatically control toast lifecycle with dismiss (animated exit) and remove (instant removal).
Dismiss a Single Toast
Triggers the exit animation, then removes after removeDelay (default 1000ms):
const toastId = toast.loading("Loading...");
// Later...
toast.dismiss(toastId);Dismiss All Toasts
Omit the id to dismiss all visible toasts at once:
toast.dismiss();Remove Toasts Instantly
To remove toasts instantly without any exit animation, use toast.remove():
// Remove a specific toast
toast.remove(toastId);
// Remove all toasts
toast.remove();Configure Remove Delay
By default, toasts are kept in the DOM for 1000ms after being dismissed (to play exit animation). Configure per-toast or globally:
// Per-toast
toast.success("Created!", { removeDelay: 500 });
// Globally via provider
<Toast23Provider
duration={5000}
// All toast options can be set as defaults
>
<App />
</Toast23Provider>Update & Deduplicate
Update an Existing Toast
Each toast call returns a unique id. Pass it as the id option to update an existing toast in-place:
const toastId = toast.loading("Loading...");
// Later, update to success
toast.success("This worked", {
id: toastId,
});Prevent Duplicate Toasts
To prevent duplicates, provide a unique permanent id. If a toast with that id already exists, it will be updated instead of creating a new one:
toast.success("Copied to clipboard!", {
id: "clipboard",
});Dark Mode
toast-23 supports dark mode in two ways:
Automatic
Respects the user's system preference via prefers-color-scheme: dark. No configuration needed.
Manual Toggle
Add the dark class to any ancestor element (typically <html>). Compatible with Tailwind CSS and Next.js themes.
Customization
toast-23 is fully customizable. Override any CSS class to match your brand or design system.
Title is Optional
Toasts work perfectly without a title — just pass your message directly:
// Without title — clean and minimal
toast.success("Changes saved successfully!");
// With title — more descriptive
toast.success("Changes saved!", {
title: "Auto-save",
});Custom Duration
Control how long each toast stays visible, or make it persistent:
// Quick notification (3 seconds)
toast("Quick message", { duration: 3000 });
// Longer display (10 seconds)
toast.info("Please read carefully", { duration: 10000 });
// Persistent — stays until manually dismissed
const id = toast.warning("Action required", { duration: 0 });
toast.dismiss(id);Dismiss Control
Choose whether users can manually dismiss a toast:
// Non-dismissible toast (no X button)
toast.info("Processing...", { dismissible: false });
// Dismissible (default behavior)
toast.success("Done!", { dismissible: true });Override Variant Colors
Customize the look of any variant by overriding its CSS class:
.toast23-item--success {
background: #d1fae5;
border-color: #6ee7b7;
}
.toast23-progress--success {
background: #10b981;
}
.toast23-icon--success {
color: #059669;
}Custom Fonts & Sizing
Change the toast font, size, border radius, or width:
.toast23-item {
font-family: "Inter", sans-serif;
border-radius: 1rem;
max-width: 400px;
}
.toast23-title {
font-size: 0.9rem;
}
.toast23-message {
font-size: 0.85rem;
}Progress Bar Styling
Adjust the progress bar height, color, or border radius:
.toast23-progress {
height: 4px;
border-radius: 0;
}
/* Custom color for all variants */
.toast23-progress--info {
background: linear-gradient(90deg, #6366f1, #8b5cf6);
}Per-Toast Position Override
Each toast can override the provider's default position:
// Default position is "top-right" from provider
toast.success("Saved!", { position: "bottom-center" });
toast.error("Oops!", { position: "top-left" });SSR Support
toast-23 is fully SSR-compatible. All browser APIs are guarded behind useEffect.
Next.js
Works with both the App Router and Pages Router. Add the provider and stylesheet in your root layout or _app.tsx.
// app/layout.tsx (App Router)
"use client";
import "toast-23/styles.css";
import { Toast23Provider } from "toast-23";
export default function RootLayout({ children }) {
return (
<html>
<body>
<Toast23Provider position="top-right">
{children}
</Toast23Provider>
</body>
</html>
);
}Remix
Import the stylesheet in your root route and wrap your Outlet with the provider.
// app/root.tsx
import "toast-23/styles.css";
import { Toast23Provider } from "toast-23";
import { Outlet } from "@remix-run/react";
export default function App() {
return (
<html>
<body>
<Toast23Provider position="top-right">
<Outlet />
</Toast23Provider>
</body>
</html>
);
}Gatsby
Use wrapRootElement in gatsby-browser.js and gatsby-ssr.js to add the provider.
// gatsby-browser.js & gatsby-ssr.js
import "toast-23/styles.css";
import React from "react";
import { Toast23Provider } from "toast-23";
export const wrapRootElement = ({ element }) => (
<Toast23Provider position="top-right">
{element}
</Toast23Provider>
);Astro
Use toast-23 inside React islands. Mark the wrapper component with client:load.
---
// src/pages/index.astro
---
<html>
<body>
<ToastWrapper client:load />
</body>
</html>// src/components/ToastWrapper.tsx
import "toast-23/styles.css";
import { Toast23Provider, useToast } from "toast-23";
function Inner() {
const toast = useToast();
return <button onClick={() => toast.success("Hello!")}>Toast</button>;
}
export default function ToastWrapper() {
return (
<Toast23Provider position="top-right">
<Inner />
</Toast23Provider>
);
}Angular
toast-23 ships a built-in createToast23() standalone API that works outside of React. No manual React root setup required — just install the peer dependencies and use the imperative API in an Angular service.
// Install peer dependencies
npm install react react-dom toast-23
npm install -D @types/react @types/react-dom// src/app/toast.service.ts
import { Injectable, OnDestroy } from '@angular/core';
import { createToast23, StandaloneToastApi } from 'toast-23';
import 'toast-23/styles.css';
@Injectable({ providedIn: 'root' })
export class ToastService implements OnDestroy {
private toast: StandaloneToastApi;
constructor() {
this.toast = createToast23({
position: 'top-right',
maxVisible: 5,
duration: 5000,
});
}
success(msg: string) { this.toast.success(msg); }
error(msg: string) { this.toast.error(msg); }
warning(msg: string) { this.toast.warning(msg); }
info(msg: string) { this.toast.info(msg); }
show(msg: string) { this.toast(msg); }
ngOnDestroy() {
this.toast.destroy();
}
}// Usage in any Angular component
import { Component } from '@angular/core';
import { ToastService } from './toast.service';
@Component({
selector: 'app-example',
template: `<button (click)="notify()">Show Toast</button>`,
})
export class ExampleComponent {
constructor(private toast: ToastService) {}
notify() {
this.toast.success('Hello from Angular!');
}
}Vue.js
Use the built-in createToast23() standalone API as a Vue plugin. No manual React root setup needed — toast-23 handles it internally.
// Install peer dependencies
npm install react react-dom toast-23
npm install -D @types/react @types/react-dom// src/plugins/toast.ts
import { Plugin, inject } from 'vue';
import { createToast23, type StandaloneToastApi } from 'toast-23';
import 'toast-23/styles.css';
const TOAST_KEY = Symbol('toast');
export const toast23Plugin: Plugin = {
install(app) {
const toast = createToast23({
position: 'top-right',
maxVisible: 5,
duration: 5000,
});
// Expose via provide/inject
app.provide(TOAST_KEY, toast);
// Cleanup on app unmount
app.config.globalProperties.$toast = toast;
const originalUnmount = app.unmount.bind(app);
app.unmount = () => {
toast.destroy();
originalUnmount();
};
},
};
export function useToast23() {
return inject<StandaloneToastApi>(TOAST_KEY)!;
}// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { toast23Plugin } from './plugins/toast';
createApp(App).use(toast23Plugin).mount('#app');<!-- ExampleComponent.vue -->
<script setup lang="ts">
import { useToast23 } from '../plugins/toast';
const toast = useToast23();
</script>
<template>
<button @click="toast.success('Hello from Vue!')">
Show Toast
</button>
</template>API Reference
Complete API documentation for every export in toast-23.
Provider Setup
<Toast23Provider>
Context provider that manages toast state and renders toast containers.
import { Toast23Provider } from "toast-23";
<Toast23Provider
position="top-right"
maxVisible={5}
duration={5000}
>
<App />
</Toast23Provider>| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | — | Your application content (required) |
| position | ToastPosition | "top-right" | Default screen corner for toasts |
| maxVisible | number | 5 | Maximum simultaneously visible toasts |
| duration | number | 5000 | Default auto-dismiss duration (ms). 0 = persistent. |
Toast Hook
useToast()
React hook that returns the ToastApi. Must be called inside a <Toast23Provider>.
import { useToast } from "toast-23";
function MyComponent() {
const toast = useToast();
// toast is a callable function with method shortcuts
}Note: Calling useToast() outside of a <Toast23Provider> will throw an error.
Standalone API
createToast23()
Standalone / imperative API for use outside React — works with Angular, Vue, Svelte, or vanilla JavaScript. Internally bootstraps a minimal React root.
import { createToast23 } from "toast-23";
import "toast-23/styles.css";
const toast = createToast23({
position: "top-right",
maxVisible: 5,
duration: 5000,
});
toast.success("Saved!");
toast.error("Oops!");
toast("Hello, world!");
// Cleanup when done
toast.destroy();| Option | Type | Default | Description |
|---|---|---|---|
| position | ToastPosition | "top-right" | Default screen corner for toasts |
| maxVisible | number | 5 | Maximum simultaneously visible toasts |
| duration | number | 5000 | Default auto-dismiss duration (ms). 0 = persistent. |
Return value: A StandaloneToastApi object with the same .success(), .error(),.warning(), .info(), .promise(), and .dismiss() methods as useToast(), plus a .destroy() method for cleanup.
Methods
ToastApi
The object returned by useToast(). A callable function with additional method properties.
| Method | Signature | Returns |
|---|---|---|
| toast() | (message: string | ReactNode, options?: ToastOptions) | string (id) |
| toast.success() | (message: string, options?) | string (id) |
| toast.error() | (message: string, options?) | string (id) |
| toast.warning() | (message: string, options?) | string (id) |
| toast.info() | (message: string, options?) | string (id) |
| toast.loading() | (message: string, options?) | string (id) |
| toast.custom() | (content: ReactNode, options?) | string (id) |
| toast.dismiss() | (id?: string) | void |
| toast.remove() | (id?: string) | void |
| toast.promise() | <T>(promise | () => Promise, opts, toastOpts?) | Promise<T> |
Options Interface
ToastOptions
Configuration object accepted by all toast methods.
interface ToastOptions {
id?: string;
title?: string;
variant?: ToastVariant;
duration?: number;
position?: ToastPosition;
dismissible?: boolean;
removeDelay?: number;
}Promise Handling
PromiseOptions<T>
Configuration for toast.promise().
interface PromiseOptions<T> {
loading: string;
success: string | ((data: T) => string);
error: string | ((err: unknown) => string);
}Type Aliases
Exported type aliases for use in your TypeScript code.
type ToastVariant = "success" | "error" | "warning" | "info" | "default";
type ToastPosition =
| "top-right" | "top-left" | "top-center"
| "bottom-right" | "bottom-left" | "bottom-center";
import type {
ToastVariant,
ToastPosition,
ToastOptions,
ToastApi,
Toast23ProviderProps,
PromiseOptions,
StandaloneOptions,
StandaloneToastApi,
} from "toast-23";CSS Class Reference
All CSS classes used by toast-23. Override these to customize the look and feel.
| Class | Description |
|---|---|
| .toast23-container | Fixed-position container |
| .toast23-container--{position} | Position modifier (top-right, etc.) |
| .toast23-item | Individual toast element |
| .toast23-item--{variant} | Variant modifier (success, error, etc.) |
| .toast23-icon | Icon wrapper |
| .toast23-content | Message content area |
| .toast23-title | Title heading |
| .toast23-message | Message body text |
| .toast23-dismiss | Dismiss button |
| .toast23-progress | Progress bar (auto-dismiss indicator) |
| .toast23-queue-badge | Queued toast count indicator |
Releases
Changelog for toast-23.
Initial Release
- ✓5 toast variants: success, error, warning, info, default
- ✓6 position options with per-toast override
- ✓Promise API with loading → success/error transitions
- ✓Loading toast shortcut
- ✓Custom JSX toasts with
toast.custom() - ✓Dismiss all / Remove instantly APIs
- ✓Update existing toasts & prevent duplicates via
id - ✓Hover-pause with smooth progress bar reversal
- ✓Dark mode (automatic + manual toggle)
- ✓Queue system with +N badge
- ✓Full TypeScript support
- ✓Accessible (ARIA live regions, keyboard support)
- ✓Zero dependencies (React peer dep only)
- ✓Standalone API for Angular, Vue, Svelte, vanilla JS
- ✓SSR compatible (Next.js, Remix, Gatsby, Astro)