javascript 48 lines · 7 steps

Building a toast notification system in React

A Context provider manages a list of transient toasts and exposes notify and dismiss to any component in the tree.

Explained by highlit
1import { createContext, useContext, useState, useCallback, useRef } from "react";
2 
3const ToastContext = createContext(null);
4 
5export function ToastProvider({ children, defaultDuration = 4000 }) {
6 const [toasts, setToasts] = useState([]);
7 const idRef = useRef(0);
8 
9 const dismiss = useCallback((id) => {
10 setToasts((prev) => prev.filter((t) => t.id !== id));
11 }, []);
12 
13 const notify = useCallback(
14 ({ message, variant = "info", duration = defaultDuration }) => {
15 const id = ++idRef.current;
16 setToasts((prev) => [...prev, { id, message, variant }]);
17 if (duration > 0) {
18 setTimeout(() => dismiss(id), duration);
19 }
20 return id;
21 },
22 [defaultDuration, dismiss]
23 );
24 
25 return (
26 <ToastContext.Provider value={{ notify, dismiss }}>
27 {children}
28 <div className="toast-viewport" role="region" aria-live="polite">
29 {toasts.map((toast) => (
30 <div key={toast.id} className={`toast toast--${toast.variant}`}>
31 <span>{toast.message}</span>
32 <button onClick={() => dismiss(toast.id)} aria-label="Dismiss">
33 ×
34 </button>
35 </div>
36 ))}
37 </div>
38 </ToastContext.Provider>
39 );
40}
41 
42export function useToast() {
43 const ctx = useContext(ToastContext);
44 if (!ctx) {
45 throw new Error("useToast must be used within a ToastProvider");
46 }
47 return ctx;
48}
01 / 01
STEP 01

Walkthrough

Space play ←→ step click any line
Three takeaways
  1. 1Context lets you expose imperative actions like notify and dismiss to the whole tree without prop drilling.
  2. 2A ref-backed counter generates stable unique ids that survive re-renders without triggering them.
  3. 3Wrapping the context in a custom hook lets you enforce correct usage with a clear error.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a toast notification system in React — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code