import { Button } from "@/components/ui/button";
import { toastManager } from "@/components/ui/toast";
export function ToastDemo() {
return (
<Button
onClick={() => {
toastManager.add({
title: "Profile Updated",
description: "Your information has been saved.",
});
}}
>
Show Toast
</Button>
);
}Installation
npm install npx shadcn@latest add @eo-n/toast Usage
Add the ToastProvider to your app layout.
import { ToastProvider } from "@/components/ui/toast";
<html lang="en">
<body>
<ToastProvider>{children}</ToastProvider>
</body>
</html>;Then use toastManager to show toasts from anywhere in your app:
import { toastManager } from "@/components/ui/toast";
toastManager.add({
title: "Profile Updated",
description: "Your changes have been saved.",
});Note
The toastManager can be called from anywhere, including outside of React
components. No hooks required.
Examples
With Action
import { Button } from "@/components/ui/button";
import { toastManager } from "@/components/ui/toast";
export function ToastWithAction() {
return (
<Button
variant="destructive"
onClick={() => {
const id = toastManager.add({
title: "Item deleted",
description: "The file has been moved to trash.",
actionProps: {
children: "Undo",
onClick: () => {
toastManager.close(id);
toastManager.add({ title: "Item restored" });
},
},
});
}}
>
Delete Item
</Button>
);
}Promise
import { Button } from "@/components/ui/button";
import { toastManager } from "@/components/ui/toast";
export function ToastPromise() {
const handleClick = () => {
toastManager.promise(
new Promise((resolve) => {
setTimeout(() => resolve("Done"), 3000);
}),
{
loading: {
title: "Loading...",
},
success: {
title: "Success!",
},
error: {
title: "Error",
},
}
);
};
return <Button onClick={handleClick}>Show Toast</Button>;
}Varying Height
Demonstrates stacking behavior with toasts of different content lengths.
import { Button } from "@/components/ui/button";
import { toastManager } from "@/components/ui/toast";
export function ToastVaryingHeight() {
return (
<Button
onClick={() => {
const description = TEXTS[Math.floor(Math.random() * TEXTS.length)];
toastManager.add({
title: "Varying Height",
description,
});
}}
>
Show Toast
</Button>
);
}
const TEXTS = [
"Short message.",
"A bit longer message that spans two lines.",
"This is a longer description that intentionally takes more vertical space to demonstrate stacking with varying heights.",
"An even longer description that should span multiple lines so we can verify the clamped collapsed height and smooth expansion animation when hovering or focusing the viewport.",
];Anchored
Anchored toasts attach to a specific element on the page, useful for contextual feedback like copy-to-clipboard actions.
"use client";
import * as React from "react";
import { Check, Copy } from "lucide-react";
import { Button } from "@/components/ui/button";
import { anchoredToastManager } from "@/components/ui/toast";
export function ToastAnchored() {
const [copied, setCopied] = React.useState(false);
const buttonRef = React.useRef<HTMLButtonElement | null>(null);
function handleCopy() {
setCopied(true);
anchoredToastManager.add({
description: "Copied to clipboard!",
positionerProps: {
anchor: buttonRef.current,
sideOffset: 8,
},
timeout: 1500,
onClose() {
setCopied(false);
},
});
}
return (
<Button
ref={buttonRef}
variant="outline"
size="icon"
onClick={handleCopy}
disabled={copied}
aria-label="Copy to clipboard"
>
{copied ? <Check className="size-4" /> : <Copy className="size-4" />}
</Button>
);
}Usage
Add the AnchoredToastProvider to your app layout (can be nested with ToastProvider):
import { AnchoredToastProvider, ToastProvider } from "@/components/ui/toast";
<ToastProvider>
<AnchoredToastProvider>{children}</AnchoredToastProvider>
</ToastProvider>;Then use anchoredToastManager with a ref to the anchor element:
import { useRef, useState } from "react";
import { anchoredToastManager } from "@/components/ui/toast";
function CopyButton() {
const [copied, setCopied] = useState(false);
const buttonRef = useRef<HTMLButtonElement>(null);
function handleCopy() {
setCopied(true);
anchoredToastManager.add({
description: "Copied to clipboard!",
positionerProps: {
anchor: buttonRef.current,
sideOffset: 8,
},
timeout: 1500,
onClose() {
setCopied(false);
},
});
}
return (
<button ref={buttonRef} onClick={handleCopy}>
Copy
</button>
);
}API Reference
Provider
Provides settings for how toasts appear and behave.
| Prop | Type | Default |
|---|---|---|
position | "top-center" | "top-right" | "top-left" | "bottom-center" | "bottom-right" | "bottom-left" | bottom-right |
richColors? | boolean | false |
closeButton? | boolean | false |
timeout? | number | 5000 |
limit? | number | 3 |
toastManager? | ToastManager | - |