JAVASCRIPT

Implement Global Theming (Light/Dark Mode) with useContext

A React hook pattern using `useContext` to manage and provide a global theme (like light/dark mode) across components, offering easy theme switching.

import React, { useState, useContext, createContext, useMemo, useCallback } from 'react';

// 1. Create a Context
const ThemeContext = createContext(null);

// 2. Create a Provider Component
export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light'); // 'light' or 'dark'

  const toggleTheme = useCallback(() => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  }, []);

  // Memoize the value to prevent unnecessary re-renders of consumers
  const contextValue = useMemo(() => ({
    theme,
    toggleTheme,
  }), [theme, toggleTheme]);

  return (
    <ThemeContext.Provider value={contextValue}>
      {children}
    </ThemeContext.Provider>
  );
}

// 3. Create a Custom Hook to consume the context
export function useTheme() {
  const context = useContext(ThemeContext);
  if (context === null) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
}

// Example Usage:
// import React from 'react';
// import { ThemeProvider, useTheme } from './useTheme'; // Assuming useTheme.js

// function ThemeSwitcher() {
//   const { theme, toggleTheme } = useTheme();
//   return (
//     <button onClick={toggleTheme}>
//       Switch to {theme === 'light' ? 'Dark' : 'Light'} Mode
//     </button>
//   );
// }

// function ThemedComponent() {
//   const { theme } = useTheme();
//   const style = {
//     padding: '20px',
//     margin: '10px',
//     borderRadius: '8px',
//     backgroundColor: theme === 'light' ? '#fff' : '#333',
//     color: theme === 'light' ? '#333' : '#fff',
//     border: `1px solid ${theme === 'light' ? '#ccc' : '#666'} `,
//   };
//   return (
//     <div style={style}>
//       This component uses the {theme} theme.
//     </div>
//   );
// }

// function AppContent() { // Renamed to avoid confusion with the main App
//   const { theme } = useTheme(); // Access theme here
//   return (
//     <div style={{ padding: '20px', minHeight: '100vh', backgroundColor: theme === 'light' ? '#f0f2f5' : '#282c34', color: theme === 'light' ? '#333' : '#f0f2f5' }}>
//       <h1>My Themed Application</h1>
//       <ThemeSwitcher />
//       <ThemedComponent />
//       <ThemedComponent />
//     </div>
//   );
// }

// function App() {
//   return (
//     <ThemeProvider>
//       <AppContent />
//     </ThemeProvider>
//   );
// }
// export default App;
How it works: This pattern demonstrates how to implement a global theming system using React's `useContext` hook. The `ThemeProvider` component wraps your application, managing the current `theme` state and providing it, along with a `toggleTheme` function, to any descendant components via the `ThemeContext`. The `useTheme` custom hook simplifies consuming this context, making it easy for components to access the theme and switch it, enabling dynamic UI changes across your application. `useMemo` is used to optimize the context value.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs