renderpx
Theme: auto

Toasts

Short-lived notifications (success, error, info) that don’t block the UI. Global trigger, stacked display, and accessible announcements.

The problem I keep seeing

After a save, delete, or error, the user needs feedback. Inline messages clutter the form; modals are heavy. You want a small, non-blocking notification (toast) that appears briefly and can be triggered from anywhere -mutations, API errors, background jobs -without passing callbacks through the tree.

Naive approach

Local state in the component that performs the action: toast message + a timeout to clear it. The toast is rendered in the same component; other parts of the app can’t trigger toasts without prop drilling or duplicating UI.

tsx
Loading...

First improvement

A toast context (or small store): expose a function like toast(message) and render a list of toasts in a single fixed container (e.g. bottom-right). Any component can call the function; toasts stack and auto-dismiss after a delay.

tsx
Loading...

Remaining issues

  • Accessibility: Toasts should be announced to screen readers (aria-live region) and not steal focus from the flow.
  • Variants: Success (green), error (red), loading, promise (loading → success/error). A small API keeps call sites clean.
  • Stacking and dismiss: Multiple toasts should stack; user may want to dismiss one or pause auto-remove.

Production pattern

Use a library: sonner, react-hot-toast, or Radix UI Toast. They provide a global toast.success() / toast.error() (and often toast.promise() for async), a single Toaster in the layout, stacking, dismiss, and aria-live. Add the provider once; call from any component or from non-React code (e.g. API client) if the library supports an imperative API.

tsx
Loading...

When I use this

  • Mutation feedback: “Saved”, “Deleted”, “Failed to save” after a button or form submit.
  • Background jobs: “Export ready”, “Sync complete” when you can’t show inline.
  • Skip when: The message is critical and must be acknowledged (use a modal or inline error). For validation errors, prefer inline near the field.

Gotchas

  • Don’t toast validation errors: Show those next to the fields or at the top of the form so the user can fix them; toasts are for success or non-field errors.
  • aria-live: Use aria-live="polite" so screen readers announce the toast without interrupting; avoid assertive unless it’s urgent.
  • Promise toasts: toast.promise(fn, { loading, success, error }) keeps the UX to one toast that updates; better than loading toast + separate success toast.

Error Boundaries → · All patterns

Related Frameworks