Overlays & navigation
Toast
Toasts confirm that something happened without interrupting the work: an invoice sent, a payment failed, an export ready. Mount one Toaster, then call toast() from any event handler or async function. Toasts stack in a corner, dismiss themselves after five seconds, pause while hovered or focused, and are announced by screen readers through a live region.
On this page
<Button variant="outline" onClick={() => toast.success("Invoice sent", { description: "INV-2041 is on its way to accounts@fernhill.example." })}> Success</Button><Button variant="outline" onClick={() => toast.error("Payment failed", { description: "The card ending in 4242 was declined. Try another card." })}> Error</Button><Button variant="outline" onClick={() => toast.info("New version available", { description: "Reload to get the latest features." })}> Info</Button><Button variant="outline" onClick={() => toast.warning("Storage almost full", { description: "You've used 92% of 5 GB." })}> Warning</Button><Button variant="outline" onClick={() => toast("Draft saved")}> Default</Button><Toaster />Usage
// app/layout.tsx: mount onceimport { Toaster } from "@/components/ui/toast"; <body> {children} <Toaster position="bottom-right" /></body> // anywhereimport { toast } from "@/components/ui/toast"; toast.success("Invoice sent", { description: "INV-2041 is on its way." });Examples
Variants
Success, error, info and warning carry an icon in their status color; the default toast is text only.
<Button variant="outline" onClick={() => toast.success("Invoice sent", { description: "INV-2041 is on its way to accounts@fernhill.example." })}> Success</Button><Button variant="outline" onClick={() => toast.error("Payment failed", { description: "The card ending in 4242 was declined. Try another card." })}> Error</Button><Button variant="outline" onClick={() => toast.info("New version available", { description: "Reload to get the latest features." })}> Info</Button><Button variant="outline" onClick={() => toast.warning("Storage almost full", { description: "You've used 92% of 5 GB." })}> Warning</Button><Button variant="outline" onClick={() => toast("Draft saved")}> Default</Button><Toaster />With an action
One action, usually Undo. Clicking it runs the callback and dismisses the toast. Don't put the only way to do something in a toast: it goes away.
INV-2041 is active.
<Button iconLeft={<Archive strokeWidth={1.75} />} disabled={archived} onClick={() => { setArchived(true); toast("Invoice archived", { description: "INV-2041 moved to Archive.", action: { label: "Undo", onClick: () => setArchived(false) }, }); }}> Archive invoice</Button>Loading and promises
toast.promise shows a spinner while the promise is pending and turns into a success or error toast in place.
<Button variant="primary" iconLeft={<Send strokeWidth={1.75} />} onClick={() => toast.promise(sendReminders(), { loading: "Sending 12 reminders…", success: "12 reminders sent", error: "Couldn't send reminders", }) }> Send reminders</Button>Persistent and updating
duration: Infinity keeps a toast until it is closed. Reusing an id replaces the toast instead of stacking a copy.
<Button variant="outline" onClick={() => toast.info("Export ready", { id: "export", description: "invoices-2024.csv · 1.2 MB", duration: Infinity, action: { label: "Download", onClick: download }, }) }> Show until dismissed</Button><Button variant="ghost" onClick={() => toast.dismiss()}> Dismiss all</Button>Props
toast()
toast(title | options)=> iddefault: —Default toast. Returns its id.toast.success / error / info / warning / loading(title, options?) => iddefault: —Same, with a variant. Loading toasts stay until updated or dismissed.toast.promise(promise, { loading, success, error }) => promisedefault: —Loading toast that resolves to success or error. Messages can be functions of the result.toast.dismiss(id?) => voiddefault: —Close one toast, or all of them without an id.useToast()() => toastdefault: —The same API as a hook.
ToastOptions
titlerequiredReactNodedefault: —One short sentence: what happened.descriptionReactNodedefault: —Details or the next step.variant"default" | "success" | "error" | "info" | "warning" | "loading"default: "default"Icon and live-region urgency.action{ label, onClick }default: —One button, e.g. Undo.durationnumberdefault: 5000Milliseconds before auto-dismiss. Infinity keeps it open.idstringdefault: —Reuse to update a toast in place.
Toaster
position"top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right"default: "bottom-right"Corner the stack grows from.maxnumberdefault: 4Toasts visible at once; older ones wait their turn.ToastProvider{ children, position?, max? }default: —Alternative that wraps your app and renders the Toaster after it.
Accessibility
- Toasts render inside a labelled region (“Notifications (F8)”) with aria-live="polite", so new messages are read without stealing focus. Error toasts use role="alert" and are announced right away.
- Press F8 to move focus to the newest toast; Tab reaches its action and the dismiss button, which is labelled “Dismiss notification”.
- Auto-dismiss pauses while the pointer is over the stack or focus is inside it, giving everyone time to read and act (WCAG 2.2.1).
- Status is never color alone: every variant has an icon and words. The region sits in the top layer, so toasts stay visible above open dialogs.