@nicojones/toast
v2.2.4
Published
A simple notification library for React. Fully customizable and lightweight.
Downloads
903
Maintainers
Readme
🌟 Features
- [x] 🪴 Ultra-lightweight core.
- [x] 🦾 Fully accessible (ARIA-friendly).
- [x] 🌓 Built-in light, dark, & system themes.
- [x] 🕶️ Pause dismissal on hover.
- [x] 🌍 Customizable toast position.
- [x] 🪞 Respects user reduced-motion settings.
- [x] 🦄 100% TypeScript.
- [x] 🧩 Can run inside Shadow Root (manually import styles).
- [x] 🎛️ Fully customizable—disable all styles if desired.
- [x] 🔄 Replace/update content of already open toasts by ID.
- [x] 🚦 Close toasts programmatically.
🚀 Getting Started
[!IMPORTANT] This library requires React v18 or higher.
- Install the library:
# Using npm:
npm install @nicojones/toast
# Using pnpm:
pnpm add @nicojones/toast
# Using yarn:
yarn install @nicojones/toast- Add the toast provider:
// 📃 root.tsx
import { Toaster } from "@nicojones/toast";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
<Toaster />
</React.StrictMode>,
);- Usage:
// 📃 index.tsx
import { toast } from "@nicojones/toast";
export default function Index() {
return (
<>
<button
onClick={() =>
toast.success({
text: "Success!",
description: "Your action was completed successfully",
})
}
>
Show Toast
</button>
</>
);
}📖 Documentation
Toast Variants
Show a toast with a specific variant:
import { toast } from "@nicojones/toast";
// Default toast
toast.default({
text: "Hello ✨",
});
// Success toast
toast.success({
text: "Success!",
description: "Operation completed successfully",
});
// Error toast
toast.error({
text: "Error!",
description: "Something went wrong",
});
// Warning toast
toast.warning({
text: "Warning!",
description: "Please check your input",
});
// Info toast
toast.info({
text: "Info",
description: "Here's some information",
});Action Buttons
Show a button and execute a custom function when clicked. The default text for the button is Action:
toast.default({
text: "A toast with action button",
action: {
content: "Action", // Button label
onClick: () => {
// Do something
console.log("Action clicked!");
},
},
});Replacing Toasts by ID
You can replace an existing toast by providing the same id. This is useful for updating progress or preventing duplicate toasts:
// First toast with ID
toast.info({
id: "update-toast",
text: "Processing...",
});
// Later, replace it with the same ID
toast.success({
id: "update-toast",
text: "Completed!",
});Toast Loading
Show a toast with loading state that automatically updates after a promise resolves or fails:
const somePromise = (): Promise<Foo> => { ... }
toast.loading<Foo>({
// Initial message:
text: "Loading",
options: {
promise: somePromise(),
success: "Ready",
error: "Error",
// Close toast automatically (the duration depends by delayDuration property):
autoDismiss: true,
// Optional:
onSuccess: (data) => {
// `data is of type Foo`
console.log("Success", data);
},
// Optional:
onError: (error, id) => {
console.log("Error", error);
// Replace the toast and use the error.message
toast.error({text: error.message, id });
},
},
});Example with async function:
const fetchData = async () => {
const response = await fetch("/api/data");
return response.json();
};
toast.loading({
text: "Fetching data",
options: {
promise: fetchData(),
success: "Data loaded",
error: "Failed to load data",
autoDismiss: true,
onSuccess: (data) => {
console.log("Received:", data);
// Replace the toast and use received data
toast.success({ text: data.message, id });
},
},
});Closing Toasts
Close a toast programmatically using toast.close():
import { toast } from "@nicojones/toast";
// Show a toast and store its ID
const toastData = toast.info({
text: "This will be closed",
});
// Close it later
toast.close(toastData.id);Or close by the ID you provided:
toast.info({
id: "my-toast",
text: "This toast has an ID",
});
// Close it using the ID
toast.close("my-toast");Custom Icon
You can use a custom icon for a toast using the icon property and passing
any valid JSX.Element.
toast.default({
text: "Party popper!",
icon: <FontAwesomeIcon width={18} height={18} icon={faPoo} />,
});Custom Attributes
You can pass custom HTML attributes to the toast:
toast.default({
text: "Custom toast",
attrs: {
"aria-customized": "yes",
"data-testid": "my-test-id",
style: {
color: "pink",
},
},
});🍞 Toaster Component
The <Toaster /> component is used to show toasts in your application. It accepts several props for customization.
Position
By default, the position is bottom-right. You can customize the position:
import { Toaster } from "@nicojones/toast";
<Toaster position="top-left" />
<Toaster position="top-right" />
<Toaster position="top-center" />
<Toaster position="bottom-left" />
<Toaster position="bottom-right" /> {/* default */}
<Toaster position="bottom-center" />Theme
You can set the theme of the toasts using the theme prop:
<Toaster theme="light" />
<Toaster theme="dark" />
<Toaster theme="system" /> {/* default */}Max Toasts
By default, the maximum number of toasts is set to 4. You can change this value:
<Toaster maxToasts={8} />Toast Options
You can customize all toasts globally using the toastOptions prop:
<Toaster
toastOptions={{
font: "font-sans",
defaultActionContent: "Close me",
defaultCloseContent: "Close",
animationOnClose: "slide", // or "swipe"
}}
/>Custom Icons
Replace the default icons for all toasts:
import { Info, CircleX, CircleAlert, CircleCheck, Loader } from "lucide-react";
<Toaster
toastOptions={{
icons: {
info: <Info className="dark:text-blue-500" />,
error: <CircleX className="text-red-500" />,
warning: <CircleAlert className="text-yellow-500" />,
success: <CircleCheck className="text-green-500" />,
loading: <Loader className="animate-spin text-gray-500" />,
},
}}
/>;Custom Styles
Extend the default styles using the classNames property:
<Toaster
toastOptions={{
classNames: {
toast: "bg-zinc-100 dark:bg-zinc-900",
container: "rounded-lg",
icon: "text-blue-500",
content: "text-sm",
actions: {
container: "flex gap-2",
closeBtn: "text-gray-500",
actionBtn: "text-blue-600",
},
},
}}
/>Headless Mode
Disable all default styles using headless property. It works together with classNames:
<Toaster
toastOptions={{
headless: true,
classNames: {
toast: "bg-white dark:bg-gray-800 rounded-lg shadow-lg p-4",
// ... other custom styles
},
}}
/>🔧 Framework Guides
Next.js
- Add the
Toasterto yourlayout.tsx:
// 📃 app/layout.tsx
import { Toaster } from "@nicojones/toast";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<Toaster />
</body>
</html>
);
}- Use the
toastfunction in client components:
"use client";
import { toast } from "@nicojones/toast";
export default function MyComponent() {
return (
<button
onClick={() =>
toast.success({
text: "Ready 🎉",
})
}
>
Click me!
</button>
);
}- (Optional) Add the styles if needed:
// 📄 app/layout.tsx
import "@nicojones/toast/dist/styles.css";Astro
- Add the
Toasterto your layout withclient:load:
// 📄 layouts/Layout.astro
---
import { Toaster } from "@nicojones/toast";
---
<!doctype html>
<html lang="en">
<body>
<slot />
<Toaster client:load />
</body>
</html>- Create a component to trigger toasts:
// 📄 components/showToast.tsx
import { toast } from "@nicojones/toast";
const ShowToast = () => {
const handleClick = () => {
toast.default({
text: "Hello from Astro!",
});
};
return (
<button type="button" onClick={handleClick}>
Show Toast
</button>
);
};
export default ShowToast;- Use the component in your pages:
// 📄 pages/index.astro
---
import Layout from "../layouts/Layout.astro";
import ShowToast from "../components/showToast";
---
<Layout title="Welcome">
<main>
<ShowToast client:load />
</main>
</Layout>📚 API Reference
toast.{variant}()
The toast function accepts the following options:
| Property | Description | Type | Required |
| --------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | -------- |
| text | Notification title | string | ✅ |
| description | Toast's description | string | - |
| icon | Icon to display in the toast | ReactNode | - |
| delayDuration | Duration before the toast disappears | number (default: 4000) | - |
| variant | Variant of the toast | Variant: info, success, warning, error or loading | - |
| theme | Theme of the toast | Theme (default: system): light, dark or system | - |
| action | Show an Action button and execute a function | { content?: string \| ReactNode, onClick: () => void \| Promise<void> } | - |
| id | Set a unique id to replace an existing toast or ensure there are no duplicates | string or number | - |
| attrs | Custom HTML attributes | HTMLProps<HTMLDivElement> | - |
toast.loading()
The toast.loading function accepts the same options as above, plus:
| Property | Description | Type | Required |
| --------- | ------------------------ | ------------- | -------- |
| options | Loading-specific options | LoadingType | - |
LoadingType
| Property | Description | Type | Required |
| ------------- | ------------------------------------------ | ------------------------------------- | -------- |
| promise | Promise or function that returns a promise | Promise<T> or () => Promise<T> | ✅ |
| success | Success message | string | ✅ |
| error | Error message | string | ✅ |
| autoDismiss | Close toast automatically after promise | boolean | ✅ |
| onSuccess | Callback when promise resolves | (data: T, id: ToastId) => void | - |
| onError | Callback when promise rejects | (error: Error, id: ToastId) => void | - |
toast.close()
Close a toast by its ID:
toast.close(id: ToastId): void<Toaster />
The <Toaster /> component accepts the following options:
| Property | Description | Type | Required |
| -------------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| theme | Theme of all toasts | Theme (default: system): 'light', 'dark', or 'system' | - |
| maxToasts | Maximum number of toasts to display | number (default: 4) | - |
| toastIcons | Replace the default icons with custom icons | Record<Variant, ReactNode> | - |
| position | Position of the toaster on the screen | Position (default: bottom-right): 'top-left', 'top-right', 'top-center', 'bottom-left', 'bottom-right' or 'bottom-center' | - |
| toastOptions | Options to customize all toasts | ToastOptions | - |
ToastOptions
| Property | Description | Type | Required |
| ---------------------- | --------------------------------------------------------------- | ---------------------------- | -------- |
| font | Font for all toasts | string | - |
| icons | Icons for all toasts | Record<Variant, ReactNode> | - |
| defaultActionContent | Default content for the action button | string or ReactNode | - |
| defaultCloseContent | Default content for the close button | string or ReactNode | - |
| headless | Disable all default styles. It works together with classNames | boolean | - |
| animationOnClose | Animation when closing toast | 'slide' or 'swipe' | - |
| classNames | Custom styles for all toasts | ToastClassnames | - |
ToastClassnames
| Property | Description | Type | Required |
| ----------- | ------------------------------------- | ------------------------------ | -------- |
| toast | Global toast style | string | - |
| container | Toast container styles | string | - |
| icon | Styles for the main icon of the toast | string | - |
| content | Styles for title and description | string | - |
| actions | Styles for the buttons | ToastActionsCustomClassnames | - |
ToastActionsCustomClassnames
| Property | Description | Type | Required |
| ----------- | ------------------------ | -------- | -------- |
| container | Action buttons container | string | - |
| closeBtn | Close button styles | string | - |
| actionBtn | Action button styles | string | - |
🤝 Contributing
- Library: React 19 with tsup + Lightning CSS + Vitest for testing.
Fork the repository.
Install dependencies:
# Install pnpm globally if you don't have it:
npm install -g pnpm
# and install dependencies:
pnpm install- Commands:
# Run packages:
pnpm dev
# Build the docs & library:
pnpm build
# Test the library:
pnpm test📃 License
MIT License - 2026.
