React cookbook · Beginner

Show toast notifications from anywhere

Display success and error messages from any component or mutation without prop drilling.

Approach

Create a small store (context + reducer or Zustand) with show()/dismiss() actions, render a toast region once near the root with role="status"/aria-live, and auto-dismiss after a timeout (pausing on hover). Expose a toast helper for non-component code like mutation callbacks.

Solution

import { create } from "zustand";

type Toast = { id: number; kind: "success" | "error"; message: string };
type ToastState = { toasts: Toast[]; show: (kind: Toast["kind"], message: string) => void; dismiss: (id: number) => void };

let nextId = 1;
export const useToasts = create<ToastState>()((set, get) => ({
  toasts: [],
  show: (kind, message) => {
    const id = nextId++;
    set((s) => ({ toasts: [...s.toasts, { id, kind, message }] }));
    setTimeout(() => get().dismiss(id), 5000);
  },
  dismiss: (id) => set((s) => ({ toasts: s.toasts.filter((t) => t.id !== id) })),
}));

export const toast = {
  success: (m: string) => useToasts.getState().show("success", m),
  error: (m: string) => useToasts.getState().show("error", m),
};

export function ToastRegion() {
  const { toasts, dismiss } = useToasts();
  return (
    <div className="toast-region" role="status" aria-live="polite">
      {toasts.map((t) => (
        <div key={t.id} className={`toast toast-${t.kind}`}>
          {t.message}
          <button aria-label="Dismiss notification" onClick={() => dismiss(t.id)}>×</button>
        </div>
      ))}
    </div>
  );
}

Pitfalls

  • Toasts as the only place important errors appear (they vanish).
  • Not announcing toasts to screen readers.
  • Stacking dozens of identical toasts — dedupe by message.

Variations

  • Use sonner or react-hot-toast libraries.
  • Use role="alert" (assertive) for errors that need immediate attention.

Further reading: MDN: ARIA status role

Reference: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/status_role

More React recipes