toast.success("Saved");
toast.error("Upload failed", {
action: { label: "Retry", onClick: retry },
duration: Infinity,
});
const id = toast.loading("Uploading...");
toast.update(id, { type: "success", message: "Uploaded" });
Keep the toast state in a tiny store outside React, so any code can call toast(). Render the toasts with one Toaster component near the root.
Requirements:
- success, error, info and loading toasts
- an optional action button
- auto-dismiss, paused on hover and focus
- stacking, with a maximum count
- callable from anywhere
Non-functional: accessible, no storms of re-renders, and small.
Architecture: the store is a module with subscribe, add, update and dismiss. Because it lives outside React, components, data-layer callbacks and plain utilities can all call toast(). A single Toaster component mounted near the root subscribes with useSyncExternalStore. It renders the toasts in a portal. Each toast has an id, type, message, duration and an optional action.
Behaviour:
- Queue toasts beyond a visible limit.
- Remove duplicate identical messages.
- Pause timers on hover, on focus, and when the tab is hidden.
- Error toasts with actions stay until the user dismisses them.
- Loading toasts can be updated in place.
Accessibility: a live region is an area that screen readers read aloud when it changes. A polite one waits for a pause. An assertive one interrupts.
- Use a polite live region for status messages, and an assertive one only for urgent errors.
- Toasts must not steal focus.
- Actions are reachable by keyboard.
- Give users enough time to read.
- Critical information never lives only in a toast.
Trade-offs: a global store is simple but implicit. App-wide inbox notifications are a different system: a separate feed backed by the server.
- Keep the store outside React, so any code can trigger toasts.
- A single
Toastersubscribes to the store withuseSyncExternalStore. - Queue and deduplicate toasts, and pause timers on hover and focus.
- Use live regions, and never steal focus.
- Never put critical information only in a toast.