Toast stack
Toasts that pile up like cards. A new one slides in at the front and pushes the rest back, each a little smaller and tucked under. Hover the pile and it fans out so you can read them all. Flick one sideways and it goes with your finger, turning as it leaves.
Installation
npx @neelshha/ui@latest add toast-stackUsage
import { ToastStack, toast } from "@/components/ui/toast-stack";
// Once, near the root of the app.
<ToastStack />
// Then from anywhere.
toast("Changes saved", { tone: "success" });The stack and toast share a store, so a toast can come from an event handler, a fetch callback, or anywhere else, without a hook or a provider.
Loading, then done
toast returns an id. Send the same id again to change that toast in place, the way the Upload button above does.
const id = toast("Uploading 3 files", { tone: "loading" });
await upload(files);
toast("3 files uploaded", { id, tone: "success" });Positions
Toasts come in from the edge they sit on, and a flick sends them off toward it.
<ToastStack position="top-center" />Keyboard
Alt+T moves focus to the main stack, and it fans out while focus is in it. Tab goes through each toast's buttons, and Escape dismisses the one with focus. When the last one goes, focus goes back to where it was. Screen readers hear new toasts without being cut off.
API
A toast's clock waits while the stack is fanned out and while the tab is hidden, so nothing goes before it's been seen. dismissToast(id) sends one away, and dismissToast() sends them all.
toast(title, options)
| Prop | Type | Default | Description |
|---|---|---|---|
description | ReactNode | A second line, under the title. | |
tone | "neutral" | "success" | "error" | "loading" | "neutral" | The icon and its colour. A loading toast stays until it changes. |
action | { label: string; onClick: () => void } | One button, like Undo. Pressing it dismisses the toast too. | |
id | string | Send a toast with the same id to change it in place. Its clock starts over. | |
duration | number | 4000 | Milliseconds on screen once it's in view. Infinity keeps it until it's dismissed. |
stack | string | "default" | The stack that shows it, for a page with more than one. |
ToastStack
Other props go to the section. --ns-toasts-width and --ns-toasts-offset set its width and its distance from the edges.
| Prop | Type | Default | Description |
|---|---|---|---|
position | "bottom-right" | "bottom-center" | "bottom-left" | "top-right" | "top-center" | "top-left" | "bottom-right" | Where on the screen it sits. Toasts flick away toward its side, or either way in the middle. |
visible | number | 3 | How many show at once. Older ones wait out of sight until those in front go. |
expand | boolean | false | Keeps the stack fanned out, not just on hover or focus. |
stack | string | "default" | Shows only the toasts sent to this stack. |