Documentation
A succinct pill toast from Pill Toaster: one frosted surface, clear status, a stacked pile that fans open, drag to dissolve into smoke. Install it from the shadcn registry.
Installation
Install with the shadcn CLI:
pnpm dlx shadcn@latest add https://toast.nabinkhair.com.np/r/pill-toaster.jsonOne self-contained file, pill-toaster.tsx. The CLI pulls the Button prerequisite automatically (registry dependency), plus motion and lucide-react from npm. Status colors use your existing theme (destructive plus the default palette), so no extra CSS setup is needed.
Mount Toasts once in your root layout:
import { Toasts } from "@/components/ui/pill-toaster"
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Toasts position="top-center" />
</body>
</html>
)
}Usage
Import the helper and fire a toast. A plain string renders without an icon; pass an object for a status, action, or custom lifetime.
import { toast } from "@/components/ui/pill-toaster"
toast("Copied")
toast({ message: "Event created", state: "success" })
toast({ message: "Something went wrong", state: "error" })Reuse an id to update a toast in place, how pending becomes success once work finishes:
const id = "creating-event"
toast({ id, message: "Saving…", state: "pending" })
await save()
toast({ id, message: "Saved", state: "success" })Types
Pick a status per toast with the state field. Actions ride along in the same object, and pending plus a reused id covers async flows.
const id = "event-created"
toast({
id,
message: "Event has been created",
state: "success",
action: {
label: "Undo",
run() {
dismissToast(id)
},
},
})Position
Control placement with the position prop on Toasts. Drag a pill in any direction to dissolve it.
<Toasts position="bottom-right" />This moves the live host, then fires a toast so you see it land there. The equivalent in your app is one line. Active: top-center
<Toasts position="top-center" />Migrate
Switching from another toast library? Copy an agent prompt, paste it into Cursor or any coding agent, and let it rewrite imports, Toasts mounts, and call sites for Pill Toaster.
- Sonner
sonner by Emil Kowalski
- react-hot-toast
react-hot-toast by Timo Lins
- shadcn/ui Toast
Toaster built on top of @base-ui/react by shadcn
Each prompt installs from the registry, maps the old API onto toast / Toasts, and calls out gaps (custom JSX bodies, duration → lifetime, promises → pending + same-id update).
API
Toasts is the host. Mount it once, it listens on a global event bus, so a second host would render every toast twice. It takes a single prop:
position— where the stack appears (defaulttop-center)
Fire with toast("message") or toast({ message, state, action, lifetime }):
state—pending(sticky),success,error,warning,info. No state renders no icon.lifetime— ms until auto-dismiss. Plain toasts live 2.4s, actions 6s.action—{ label, run }. The toast dismisses afterrununless it re-issues the same id.id— reuse to update a toast in place instead of adding a new one.dismissToast(id)— dismiss one toast programmatically.
Multiple toasts collapse into a peeking pile and fan out when hovered, focused, or pressed (which also pauses timers). Drag a pill past the threshold and it dissolves into smoke. Pure helpers upsertToast, dismissDelay, tick, pileSlot, and fanSlot are exported for testing.