Toast
Quiet confirmations that stack into a deck, fan out on hover and swipe away.
Installation
npx shadcn@latest add @quireui/toastUsage
Wrap the app once and place the Toaster where toasts should appear:
<ToastProvider>
<App />
<Toaster />
</ToastProvider>Then call toast from anywhere, including outside components, like a data layer or an event handler:
toast.success("Invoice sent", { description: "Northwind Traders gets it in a minute." });Types
toast() for a plain message, and toast.success, .error, .info and .loading for an icon with timing to match. For measurable work there is toast.progress, below. Most close after 5 seconds. Errors stay for 8 seconds and are announced straight away to screen readers, because an error that disappears unread is worse than one that waits. Loading toasts stay until you update them with toast.update(id, title, { type }).
Promises
toast.promise shows a loading toast and turns it into success or error when the promise settles. The messages can use the result.
toast.promise(exportInvoices(), {
loading: "Exporting invoices",
success: (count) => `Exported ${count} invoices`,
error: "Export failed",
});Progress
toast.progress is for work you can measure, like an upload or an import. It shows a bar and a small line under the title: the percentage by default, or your own detail for steps. It returns a handle to move it along and finish it; finishing drops the bar and the action and starts the normal timer.
const upload = toast.progress("Uploading receipts", {
detail: "0 of 12",
action: { label: "Cancel", onClick: cancelUpload },
});
upload.update(5 / 12, "5 of 12");
upload.success("Uploaded 12 receipts");value runs from 0 to 1. The bar eases between updates, so progress that arrives in bursts still moves smoothly. When you cannot measure the work, use toast.loading instead: a bar that guesses is worse than a spinner that is honest.
Undo
Pass an action for one inline button. Clicking it runs onClick and closes the toast. Keep it to quick reversals, like Undo after archiving; anything bigger belongs in the page.
toast("Invoice archived", {
action: { label: "Undo", onClick: () => restore(invoice) },
});The stack
New toasts slide in at the front. Older ones tuck behind as a deck, a little higher and smaller, with their text hidden so the stack stays calm. Hover or focus the stack and it fans out into a full list; timers pause while you read, and when the window is in the background. Past limit (3 by default, on ToastProvider) the oldest ones fade out.
Dismissing
Swipe a toast right or down and it follows your finger, fading as it goes, then carries on in that direction. On a desktop, the close button appears on hover; on touch screens it is always there.
Position
position on Toaster: bottom-right (default), bottom-left, bottom-center, top-right, top-left or top-center. Top positions stack downward with the same deck.
Accessibility
Toasts are read politely as they arrive. Errors, and anything with priority: "high", are read straight away. Each toast is named by its title and description, and a progress toast is a progress bar that reads its detail, like "5 of 12".
| Key | Action |
|---|---|
| F6 | Moves focus to the toasts, which also fans out the stack and pauses the timers. |
| Tab / Shift+Tab | Moves through the toasts, each toast and then its action and close button. |
| Esc | With focus in the toasts, returns focus to where it was. |
| Enter / Space | Runs the focused action or close button. |
Motion
Toasts slide in from their edge in 220ms, and the icon stamps in just after, so the result lands as its own moment. A loading toast that resolves stamps its new icon the same way. The deck fans out and back on the same curve.
Closing takes 160ms rather than the library's usual 110ms exit: the toast sinks back and shrinks a little, like it is put away, because a toast is usually closed while you are looking at it and anything faster reads as a blink. While you swipe, the toast fades with distance; once it is past the point where letting go dismisses it, it is at about half strength. Let go before that and it springs back.
Under reduced motion they only fade; the stack still lays out the same, it just does not move between states.
API reference
ToastProvider
Wrap the app once. limit is how many toasts show before the oldest hide; defaults to 3.
Also takes every prop of Base UI's Toast.Provider.
Toaster
Where toasts appear. Place it once, inside ToastProvider.
Prop
Type
Style it with [data-slot="toaster"].