app/
│
├── layout.jsx
├── page.jsx
├── error.jsx               ← Route-level error boundary (optional per route)
├── global-error.jsx        ← App-wide error boundary (required for global fallback)
│
└── components/
    ├── GlobalErrorContext.jsx
    ├── GlobalErrorToast.jsx
    └── ErrorBoundary.jsx   ← Optional custom boundary for components
Catches rendering errors only in this route. Automatically receives
{ error, reset }from Next.js.
'use client';
import { useEffect } from 'react';
export default function Error({ error, reset }) {
  useEffect(() => {
    console.error('Route Error:', error);
  }, [error]);
  return (
    <div className="min-h-screen flex items-center justify-center bg-gray-50 p-6">
      <div className="bg-white shadow-xl rounded-2xl p-8 max-w-md text-center border border-gray-200">
        <h2 className="text-2xl font-semibold text-gray-800 mb-3">
          Something went wrong 😕
        </h2>
        <p className="text-gray-600 mb-6">
          {error?.message || 'An unexpected issue occurred in this page.'}
        </p>
        <button
          onClick={() => reset()}
          className="px-5 py-2 rounded-lg bg-indigo-600 text-white hover:bg-indigo-700 transition active:scale-95">
          Try again
        </button>
      </div>
    </div>
  );
}✅ Features
- Simple recovery (reset()re-renders route)
- Tailwind styling for clean layout
- Minimal, non-blocking fallback
Catches uncaught errors across your whole app. Must include
<html>and<body>in return.
'use client';
export default function GlobalError({ error, reset }) {
  console.error('Global Error:', error);
  return (
    <html>
      <body className="min-h-screen flex items-center justify-center bg-gray-900 text-white">
        <div className="bg-gray-800 p-8 rounded-2xl shadow-2xl max-w-lg text-center border border-gray-700">
          <h2 className="text-3xl font-semibold mb-3">⚠️ Application Error</h2>
          <p className="text-gray-300 mb-5">
            {error?.message ||
              'A critical error has occurred. Please reload the app.'}
          </p>
          <button
            onClick={() => reset()}
            className="px-6 py-2 rounded-lg bg-red-600 hover:bg-red-700 transition active:scale-95">
            Reload App
          </button>
        </div>
      </body>
    </html>
  );
}✅ Features
- Handles global uncaught errors (including layout crashes)
- Styled distinctly (dark theme)
- Encourages full reload rather than just retry
For non-crashing errors, like API or validation issues — you don’t want to break the whole page.
components/GlobalErrorContext.jsx:
'use client';
import { createContext, useContext, useState, useCallback } from 'react';
const GlobalErrorContext = createContext();
export function GlobalErrorProvider({ children }) {
  const [errors, setErrors] = useState([]);
  const push = useCallback((message, meta) => {
    const id = Date.now() + Math.random();
    setErrors((prev) => [{ id, message, meta }, ...prev]);
  }, []);
  const dismiss = useCallback((id) => {
    setErrors((prev) => prev.filter((e) => e.id !== id));
  }, []);
  return (
    <GlobalErrorContext.Provider value={{ errors, push, dismiss }}>
      {children}
    </GlobalErrorContext.Provider>
  );
}
export const useGlobalError = () => useContext(GlobalErrorContext);components/GlobalErrorToast.jsx:
'use client';
import { useGlobalError } from './GlobalErrorContext';
export function GlobalErrorToast() {
  const { errors, dismiss } = useGlobalError();
  if (!errors.length) return null;
  return (
    <div className="fixed top-4 right-4 z-50 flex flex-col gap-3">
      {errors.map((e) => (
        <div
          key={e.id}
          className="bg-red-50 border border-red-200 text-red-700 rounded-lg shadow-md p-4 max-w-sm w-full">
          <div className="flex justify-between items-start">
            <div>
              <p className="font-semibold">Error</p>
              <p className="text-sm">{e.message}</p>
              {e.meta && (
                <pre className="text-xs mt-2 bg-white p-2 rounded text-gray-600 overflow-auto">
                  {JSON.stringify(e.meta, null, 2)}
                </pre>
              )}
            </div>
            <button
              onClick={() => dismiss(e.id)}
              className="text-xs bg-white px-2 py-1 rounded-md border hover:bg-gray-100">
              Close
            </button>
          </div>
        </div>
      ))}
    </div>
  );
}app/layout.jsx:
import './globals.css';
import { GlobalErrorProvider } from '@/components/GlobalErrorContext';
import { GlobalErrorToast } from '@/components/GlobalErrorToast';
export const metadata = {
  title: 'My Next.js App',
  description: 'Error-handling setup demo',
};
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <GlobalErrorProvider>
          {children}
          <GlobalErrorToast />
        </GlobalErrorProvider>
      </body>
    </html>
  );
}'use client';
import { useGlobalError } from '@/components/GlobalErrorContext';
export default function Example() {
  const { push } = useGlobalError();
  async function handleClick() {
    try {
      // simulate API error
      throw new Error('Failed to fetch user data');
    } catch (err) {
      push(err.message, { endpoint: '/api/user' });
    }
  }
  return (
    <div className="p-8">
      <button
        onClick={handleClick}
        className="px-5 py-2 rounded-lg bg-indigo-600 text-white hover:bg-indigo-700">
        Trigger Error Toast
      </button>
    </div>
  );
}- 
Colors: - Route errors → Light background (bg-gray-50)
- Global errors → Dark background (bg-gray-900)
- Toasts → Subtle red (bg-red-50,border-red-200)
 
- Route errors → Light background (
- 
Consistency: use rounded-xl, shadow-lg, and transitions 
- 
Accessibility: - Add role="alert"to toasts
- Keep focus on retry buttons when possible
 
- Add 
If you want to catch errors within components (not route-level):
components/ErrorBoundary.jsx:
'use client';
import React from 'react';
export class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }
  static getDerivedStateFromError(error) {
    return { error };
  }
  render() {
    if (this.state.error) {
      return (
        <div className="p-6 bg-red-50 border border-red-200 rounded-lg text-red-700">
          <p>Component failed to render.</p>
          <p className="text-sm">{this.state.error.message}</p>
        </div>
      );
    }
    return this.props.children;
  }
}Use:
<ErrorBoundary>
  <Widget />
</ErrorBoundary>| Scope | File | Purpose | Recovery | 
|---|---|---|---|
| Component | ErrorBoundary.jsx | Catches component crashes | Manual | 
| Route | app/error.jsx | Handles route-level render errors | reset() | 
| Global | app/global-error.jsx | Handles entire app crashes | reset()reloads | 
| Toast System | GlobalErrorContext.jsx,GlobalErrorToast.jsx | Shows recoverable API/UI errors | Dismiss button | 
Would you like me to give you a ready-made “/components/errors” folder zip (with all these files structured and styled together)? I can generate it so you can drop it into your project directly.
An Error Boundary is a React component that catches JavaScript errors in its child components’ rendering phase (and lifecycle methods), preventing the entire app from crashing.
It’s like a “try-catch” for React UI.
Use <ErrorBoundary> around risky components — ones that may fail due to:
- API data issues (e.g., bad response, null values)
- Third-party widgets
- Dynamically loaded components
- Experimental / unstable features
Example:
<ErrorBoundary>
  <UserProfile userId={id} />
</ErrorBoundary>If UserProfile crashes while rendering (say, due to user.name being undefined),
the error is caught and a friendly fallback UI is shown — not a blank white screen.
'use client';
import React from 'react';
export class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  static getDerivedStateFromError(error) {
    // Update state so next render shows fallback
    return { hasError: true, error };
  }
  componentDidCatch(error, info) {
    console.error('Error caught by boundary:', error, info);
    // Optionally log to monitoring service (Sentry, LogRocket, etc.)
  }
  handleReset = () => {
    this.setState({ hasError: false, error: null });
  };
  render() {
    if (this.state.hasError) {
      return (
        <div className="p-6 bg-red-50 border border-red-200 rounded-xl text-red-700 text-center">
          <h2 className="font-semibold mb-2">Component Error</h2>
          <p className="text-sm mb-4">{this.state.error?.message}</p>
          <button
            onClick={this.handleReset}
            className="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">
            Try Again
          </button>
        </div>
      );
    }
    return this.props.children;
  }
}Here’s the basic usage syntax:
import { ErrorBoundary } from '@/components/ErrorBoundary';
import Widget from '@/components/Widget';
export default function Dashboard() {
  return (
    <div className="space-y-6">
      <ErrorBoundary>
        <Widget />
      </ErrorBoundary>
      <ErrorBoundary>
        <AnotherWidget />
      </ErrorBoundary>
    </div>
  );
}- Each ErrorBoundaryisolates errors to its child.
- If <Widget />crashes, it won’t affect<AnotherWidget />or the rest of the page.
- You can show fallback UI like “Something went wrong in this widget.”
You can pass a custom fallback component for flexibility.
function Fallback({ error, reset }) {
  return (
    <div className="bg-yellow-50 border border-yellow-200 p-4 rounded-lg">
      <p className="text-yellow-700">Oops! {error.message}</p>
      <button onClick={reset} className="text-sm text-yellow-600 underline">
        Retry
      </button>
    </div>
  );
}
<ErrorBoundary fallback={<Fallback />}>
  <Widget />
</ErrorBoundary>;✅ Caught:
- Rendering errors in React components
- Errors in lifecycle methods
- Errors in constructors of child components
❌ Not caught:
- Asynchronous errors (e.g., in fetch,setTimeout)
- Event handler errors (you handle those with try-catch manually)
- Errors outside the React tree
Example:
try {
  await fetch('/api');
} catch (err) {
  // Handle manually or via GlobalErrorContext
}| Level | File | Purpose | 
|---|---|---|
| Component | <ErrorBoundary> | Local errors (small scope) | 
| Route | app/error.jsx | Page-level errors | 
| Global | app/global-error.jsx | Entire app fallback | 
You can nest them safely. Example:
<ErrorBoundary>
  <Suspense fallback={<Loading />}>
    <PageContent />
  </Suspense>
</ErrorBoundary>Imagine a dashboard with multiple independent widgets:
export default function Dashboard() {
  return (
    <div className="grid grid-cols-2 gap-6 p-6">
      <ErrorBoundary>
        <WeatherWidget />
      </ErrorBoundary>
      <ErrorBoundary>
        <StockWidget />
      </ErrorBoundary>
      <ErrorBoundary>
        <NewsWidget />
      </ErrorBoundary>
    </div>
  );
}If StockWidget fails (e.g., API error or undefined data),
only its tile shows an error message — the rest continue to work.
| Concept | Description | 
|---|---|
| <ErrorBoundary> | A React “try-catch” for UI rendering | 
| Placement | Around risky or isolated components | 
| Benefit | Prevents app crashes, improves UX | 
| error.jsx | Next.js built-in route boundary | 
| global-error.jsx | App-wide error fallback | 
| Together | You can mix all for layered protection | 
to appear as your Next.js website favicon, and for that favicon to automatically change color in light/dark mode using your CSS variables:
--color-minion-yellow: #f0db4f;
--color-dark-charcoal: #323330;Perfectly doable ✅ Let’s go step-by-step so it works cleanly in Next.js.
Since browser favicons don’t dynamically read Tailwind or CSS variables, the best way is to make two small SVG files that use your colors directly.
In your public/ folder, create:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
  <rect width="128" height="128" rx="12" fill="#f0db4f"/>
  <path fill="#323330" d="M80.6 97.4c2.3 3.7 5.3 6.4 10.6 6.4 4.5 0 7.4-2.3 7.4-5.5 0-3.8-3-5.2-8.1-7.4l-2.8-1.2c-8.1-3.5-13.5-7.8-13.5-17 0-8.5 6.5-15 16.8-15 7.3 0 12.6 2.5 16.4 9l-9 5.8c-2-3.5-4.1-4.9-7.4-4.9s-5.3 2.1-5.3 4.9c0 3.4 2.1 4.8 6.9 6.9l2.8 1.2c9.6 4.1 15 8.3 15 17.7 0 10.1-7.9 15.6-18.4 15.6-10.3 0-17-4.9-20.3-11.3l8.9-5.8zM43.4 98.2c1.7 3 3.2 5.5 6.9 5.5 3.5 0 5.7-1.4 5.7-6.9V57.3h10.6v40.1c0 11-6.5 16-15.9 16-8.5 0-13.4-4.4-15.9-9.7l8.6-5.5z"/>
</svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
  <rect width="128" height="128" rx="12" fill="#323330"/>
  <path fill="#f0db4f" d="M80.6 97.4c2.3 3.7 5.3 6.4 10.6 6.4 4.5 0 7.4-2.3 7.4-5.5 0-3.8-3-5.2-8.1-7.4l-2.8-1.2c-8.1-3.5-13.5-7.8-13.5-17 0-8.5 6.5-15 16.8-15 7.3 0 12.6 2.5 16.4 9l-9 5.8c-2-3.5-4.1-4.9-7.4-4.9s-5.3 2.1-5.3 4.9c0 3.4 2.1 4.8 6.9 6.9l2.8 1.2c9.6 4.1 15 8.3 15 17.7 0 10.1-7.9 15.6-18.4 15.6-10.3 0-17-4.9-20.3-11.3l8.9-5.8zM43.4 98.2c1.7 3 3.2 5.5 6.9 5.5 3.5 0 5.7-1.4 5.7-6.9V57.3h10.6v40.1c0 11-6.5 16-15.9 16-8.5 0-13.4-4.4-15.9-9.7l8.6-5.5z"/>
</svg>In Next.js 13+ (App Router), you can do this neatly in app/layout.js (or app/layout.tsx):
export const metadata = {
  title: 'My JavaScript Site',
  icons: {
    icon: [
      { url: '/favicon-light.svg', media: '(prefers-color-scheme: light)' },
      { url: '/favicon-dark.svg', media: '(prefers-color-scheme: dark)' },
    ],
  },
};This tells the browser to automatically switch the favicon based on user theme 🌞🌙.