Skip to main content

Command Palette

Search for a command to run...

Step-by-Step Guide to Light/Dark Theme Toggle with React Context API

Updated
4 min read
Step-by-Step Guide to Light/Dark Theme Toggle with React Context API

» In modern React applications, state management plays a crucial role. As applications grow larger, prop drilling (passing props down multiple levels) becomes a nightmare. This is where the React Context API shines — it provides a clean and powerful way to share state across components without unnecessary prop drilling.

» In this article, we will dive deep into the Context API with an easy-to-understand Light/Dark Theme Toggle example. Along the way, we’ll explore how it works, why it’s useful, and best practices you can apply in real-world projects.

🔹 What is the Context API?

The Context API is a built-in feature in React that allows you to create global state accessible by any component in the component tree, without passing props manually at every level.

  • Think of Context as a “global store” for React components.

  • It allows data sharing across deeply nested components.

  • It’s a great alternative for simpler use cases where using heavy libraries like Redux or Zustand might be overkill.

🔹 Steps to Use Context API

There are 3 main steps:

  1. Create a Context using createContext().

  2. Provide the Context using Context.Provider.

  3. Consume the Context using useContext().

Let’s break it down with the Theme Toggle example.

🔹 Step 1: Creating the Context & Provider

import React, { createContext, useState } from 'react'

// Step 1: Create Context
export let ThemeContext = createContext('')

const ThemeProvider = ({children}) => {
  let [theme, setTheme] = useState('light')

  // Step 2: Define logic to toggle theme
  let handleTheme = () => {
    setTheme((theme) => theme === "light" ? "dark" : "light")
  }

  return (
    // Step 3: Provide the context value
    <ThemeContext.Provider value={{ theme, handleTheme }}>
      {children}
    </ThemeContext.Provider>
  )
}

export default ThemeProvider

Here’s what’s happening:

  • ThemeContext is created using createContext().

  • ThemeProvider is a wrapper component that manages the theme state and provides it to all children components.

  • The value prop of ThemeContext.Provider contains both theme and the handleTheme function.

🔹 Step 2: Wrapping the App with Provider

import React from 'react'
import ThemeProvider from './ThemeProvider'
import Home from './Home'
import Profile from './Profile'

const App = () => {
  return (
    <ThemeProvider>
      <Home />
      <Profile />
    </ThemeProvider>
  )
}

export default App

Here we wrap <Home/> , <Profile/> with <ThemeProvider>.
This means all components inside ThemeProvider can now access theme and handleTheme directly.

Step 3: Consuming the Context

import React, { useContext } from 'react'
import { ThemeContext } from './ThemeProvider'

const Profile = () => {
  let { theme } = useContext(ThemeContext)

  let styles = {
    background: theme === "light" ? "#f0f0f0" : "#444",
    color: theme === "light" ? "#111" : "#eee",
    padding: "30px",
    textAlign: "center",
    borderRadius: "10px",
    marginTop: "20px"
  }

  return (
    <div style={styles}>
      <h2>Profile Section</h2>
      <p>This section also follows the <b>{theme.toUpperCase()} MODE</b>.</p>
    </div>
  )
}

export default Profile
import React, { useContext } from 'react'
import { ThemeContext } from './ThemeProvider'

const Home = () => {
  let { theme, handleTheme } = useContext(ThemeContext)

  let styles = {
    background: theme === "light" ? "#fff" : "#333",
    color: theme === "light" ? "#333" : "#fff",
    padding: "50px",
    textAlign: "center"
  }

  return (
    <div style={styles}>
      <h1>{theme.toUpperCase()} MODE</h1>
      <button onClick={handleTheme}>Toggle Theme</button>
    </div>
  )
}

export default Home
  • useContext(ThemeContext) is used to consume the context.

  • Now, theme and handleTheme are available inside the Home and profile component.

  • The UI dynamically switches between Light Mode and Dark Mode when the button is clicked.

🔹 Benefits of Using Context API

No more prop drilling – Pass data once at the top and consume it anywhere.
Simple state management – Great for small to medium-scale apps.
Improves maintainability – Your code is cleaner, modular, and reusable.
Performance friendly – React ensures only the necessary components re-render.

🔹 When to Use Context API?

  • When global state is required across multiple components (e.g., theme, authentication, language preference).

  • When you want to avoid Redux/other state libraries for small projects.

  • When data sharing between non-parent-child components is necessary.

⚠️ Caution: Don’t overuse Context API for everything. For large-scale applications with complex business logic, Redux Toolkit, Zustand, or Recoil might be better choices.

🔹 Final Thoughts

The React Context API is a game-changer for state management when used correctly. Our Theme Toggle example is simple, yet powerful enough to demonstrate how Context helps us manage shared state.

If you’re building a real-world application, consider combining Context with other tools (like custom hooks, reducers, or middleware) for even greater flexibility.

By mastering Context API, you’ll take one more step toward becoming a pro-level React developer.

More from this blog

Bodhitech

7 posts

Technology with Knowledge & Awareness.