---
title: 'Toggle Dark Mode'
created: '2019-08-31T20:22:37.000Z'
edited: '2020-01-13T22:36:19.110Z'
description: 'How to create your own Context to toggle dark mode using styled-components.'
keywords: styled-components, react, dark mode, theme, context, useContext, useState, useEffect, localStorage
---
So you are creating your own website and you decide to have a dark and light theme, there might be a few questions that pop on your mind. How do I switch between them? Do I need to store them in a global state manager like Redux or MobX? How to integrate it with my styling solution?
In this blog post I intend on clarifying how I used `Context` and `useContext` to store the current state of this website's theme toggle.
To achieve our goal we will use `styled-components` and `react`. You may switch styled-components to vanilla `css` and dynamically assign **css-variables** in order to effectively change your theme, some adjustments are required, but the main `Context` concept will be the same.
## Setting Up
We will start by creating two **theme** objects:
```js {2,9}
const darkTheme = {
isDark: true,
background: 'black',
primary: 'lightblue',
secondary: 'pink',
}
const lightTheme = {
isDark: false,
background: 'white',
primary: 'royalblue',
secondary: 'palevioletred',
}
```
Note the `isDark` property above, that is there so you can easily check if the theme is dark through the `theme` object, which is provided to every `styled-component`.
With that done, we will need to check if the user has a saved preference from previous visits and the system's **prefers-color-scheme** value. I use `localStorage` for storing preference, but you can use any type of storage you want.
```js
// We don't parse it because "unset" is also a valid value
const savedIsDarkMode = localStorage.getItem('dark')
// Here we leverage matchMedia API to check if the system prefers dark mode
const prefersDarkMode = matchMedia('(prefers-color-scheme: dark)').matches
```
With those values in hand, we can get an usable `isDarkMode` value
```js
// Get usable isDarkMode
const getIsDarkMode = () => {
// Checks if user has a preference already set and use it
// If not set, then try to select mode by detecting system preference
switch (savedIsDarkMode) {
case 'true':
return true
case 'false':
return false
default:
return prefersDarkMode
}
}
```
With these values in hand, we are ready to create the react context necessary to store our dark mode state, this can be achieved with the code bellow
```js
export const ThemeModeContext = React.createContext({
theme: getIsDarkMode() ? darkTheme : lightTheme,
setIsDarkMode: () => {},
})
```
The `ThemeModeContext` can be imported and used with [useContext](https://reactjs.org/docs/context.html#reactcreatecontext) in order to call `setIsDarkMode` from within the app. We initialized the values merely as a formality, so we know the object shape.
## Who Provides the Providers?
We are ready to create the mighty `ThemeModeProvider`, which will encapsulate all of our application's code.
```jsx
export const ThemeModeProvider = ({ children }) => {
const [isDarkMode, setIsDarkMode] = useState(getIsDarkMode())
useEffect(() => {
localStorage.setItem('dark', JSON.stringify(isDarkMode))
}, [isDarkMode])
const mode = {
theme: isDarkMode ? darkTheme : lightTheme,
setIsDarkMode,
}
return (
{children}
)
}
```
Take a look at the code above, it looks quite simple if you are comfortable with **hooks** and **context**, but we are going to dissect the component anyway for those who missed on that.
First we have `useState` which was initialized with the value from `getIsDarkMode()`. We do this so the state always has the correct value on initialization. Assuming `getIsDarkMode()` returns `true`, we then have:
```js
const [isDarkMode, setIsDarkMode] = useState(getIsDarkMode())
// [true, (state) => newState]
```
This is the basics of [useState](https://reactjs.org/docs/hooks-reference.html#usestate). It takes in an initial value and returns an array with the signature `[currentState, updateStateFunction]`, we can then call `updateStateFunction('newValue')`, and `currentState` will be updated to equal `'newValue'` on the next render.
Next in line we have [useEffect](https://reactjs.org/docs/hooks-reference.html#useeffect), which is basically a function that says **run this whenever any value in the dependency array change**.
```js
useEffect(() => {
localStorage.setItem('dark', JSON.stringify(isDarkMode))
}, [isDarkMode])
```
What we are saying with the above code is: When `isDarkMode` changes, set the `localStorage` value to the new `isDarkMode` value. This ensures that the user preference is always updated.
Lastly we have the `Context.Provider` itself. As its name implies, it is used to provide `Context.Consumer`'s with a value. `` and `useContext(ThemeModeContext)` will only have a value if the the provider is present in the tree **above the consumer**. `ThemeProvider` is used to enable custom styled-components themes and mostly works like any other context.
```jsx
{children}
```
Now that you have a better understanding of what the provider does, you need to encapsulate the root of your application with the `ThemeModeProvider` component. In a regular [create-react-app](https://create-react-app.dev/) app, it will be something like this:
```jsx
ReactDOM.render(
,
document.getElementById('root')
)
```
## Consuming the Context
In order to actually use the context in one of your components, you can either use `Context.Consumer` component or `useContext` hook, I will only show how to use the hook implementation as it is much simpler and more straightforward.
Anywhere you want to be able to change the current theme, be it a `button` or a `toggle` like in the top of this page, just call `useContext(ThemeModeContext)` and you will have access to the `setIsDarkMode` function.
```jsx {5}
import React, { useContext } from 'react'
import { ThemeModeContext } from './theme'
export const Buttons = () => {
const { setIsDarkMode } = useContext(ThemeModeContext)
const setDark = () => setIsDarkMode(true)
const setLight = () => setIsDarkMode(false)
const toggleMode = () => setIsDarkMode((s) => !s)
return (
<>
>
)
}
```
These are all the parts needed to create a fairly simple dark mode toggle. You can, of course, improve and simplify steps as you see fit. To check an actual usage of the code you can check the **Code Sandbox** bellow.