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:
Create a Context using
createContext().Provide the Context using
Context.Provider.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:
ThemeContextis created usingcreateContext().ThemeProvideris a wrapper component that manages thethemestate and provides it to all children components.The
valueprop ofThemeContext.Providercontains boththemeand thehandleThemefunction.
🔹 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,
themeandhandleThemeare available inside theHomeandprofilecomponent.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.




