Light/Dark Mode toggle in React JS using Context API
Tags: react, javascript, codenewbie
Published: 2020-10-25 12:40:37

Hello **Dev**,
Now a days most of the websites have ***dark and light mode***. In this post we will learn how to do that in your React application using the **Context API**.

Packages:

1. 
 [react-switch](https://www.npmjs.com/package/react-switch) To implement the toggle switch (you can use button also)

2. 
 [react-icons](https://www.npmjs.com/package/react-icons) To use sunny and moon icon (you can use any icon packages)


> 
A quick [demo](https://theme-context-api.vercel.app/) 


> 
To access the repo  [here](https://gitlab.com/pixie-dev/theme-using-context-api)

**Concept to understand here:**

- 
Context API - Provider and Consumer. 

- 
The Provider act as a Global state. So the Root component of the project should be wrapped by the Provider

- 
Access the values stored in the provider using the Consumer at anywhere in your component


- 
The provider always holds the value(state) and methods that modify the state



### First create a Provider.js
`Provider.js`

```
import React, { useState, createContext } from "react";

export const ThemeContext = createContext();

const ThemeProvider = ({ children }) => {
  const [mode, setTheme] = useState("light");
  return (
    <ThemeContext.Provider
      value={{
        mode,
        setTheme: () => setTheme(mode === "dark" ? "light" : "dark")
      }}
    >
      {children}
    </ThemeContext.Provider>
  );
};

export default ThemeProvider;

``` 

`createContext()` creates a context object. Then defining a `state` named `mode` by default it as **light** value. And the `setTheme` is an action that modifies the `mode` value.
Then creating the Provider component by default it accepts `value` as a prop. Notice that: The `value` prop has `mode` and `setTheme` properties.

The provider component returns a `children`. i.e where ever we wrap this provider that component will be considered as `root` of this context provider.

From the above code we initialized `ThemeContext` and Created our `ThemeProvider`.


### Create theme.js

`theme.js`
```
export const theme = {
  light: {
    color: "#03dac5",
    backgroundColor: "#ffffff",
    highlight: "#fdb813"
  },
  dark: {
    color: "#bb86fc",
    backgroundColor: "#121212",
    highlight: "#ffffff"
  }
};
``` 
Theme is just an `object` containing values corresponding to the modes.


### Wrap the ThemeProvider in the root component

`index.js`
```
import React from "react";
import ReactDOM from "react-dom";

import App from "./App";

import ThemeProvider from "./Provider";

const rootElement = document.getElementById("root");
ReactDOM.render(
  <ThemeProvider>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </ThemeProvider>,
  rootElement
);

``` 
Here, the root component is `index.js`. Now the Provider is available globally, we can use the consumer in any where inside our components to access the `value` from the provider.


### Access the values from the provider
`App.js`
```
import React, { useContext } from "react";

import { theme } from "./theme";

import { ThemeContext } from "./Provider";

const getStyles = (mode) => ({
  header: {
    fontSize: 34,
    fontWeight: "400"
  },
  app: {
    height: "100%",
    width: "100%",
    padding: 16,
    backgroundColor: theme[mode].backgroundColor
  },
  text: {
    fontWeight: "200",
    color: theme[mode].color
  },
  theme: {
    color: theme[mode].highlight
  }
});

export default function App() {
  const { mode } = useContext(ThemeContext);
  const styles = getStyles(mode);
  return (
    <div style={styles.app}>
      <h1 style={(styles.header, styles.text)}>
        Have a nice day... DEV!
      </h1>
      <h2 style={styles.text}>
        Current theme is <span style={styles.theme}>{mode}</span> mode
      </h2>
    </div>
  );
}

``` 

From the above code, we are trying to access the `mode` value. So at first we need to say what context object we are trying to access(ThemeContext).

You notice that, `mode` value is passed to `styles`, here based on the `mode` we are changing the text color and background color.

### Time to create a toggle switch
`ThemeSwitch.js`
```
import React, { useContext } from "react";

import Switch from "react-switch";
import { IoMdSunny, IoMdMoon } from "react-icons/all";

import { ThemeContext } from "./Provider";

const getStyles = (mode) => ({
  switch: {
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    height: "100%",
    fontSize: 35,
    paddingLeft: mode === "dark" ? 30 : 10
  }
});

const ThemeSwitch = () => {
  const { setTheme, mode } = useContext(ThemeContext);
  const styles = getStyles(mode);
  return (
    <Switch
      checked={mode === "light" ? true : false}
      height={50}
      width={120}
      offColor="#1d1f2f"
      onColor="#FDB813"
      checkedIcon={
        <IoMdSunny style={styles.switch} color="white" className="light" />
      }
      uncheckedIcon={
        <IoMdMoon style={styles.switch} color="white" className="dark" />
      }
      onChange={setTheme}
    />
  );
};

export default ThemeSwitch;


``` 
Here, we are handling the `setTheme` method when the toggle switch is clicked. And based on the `mode` we are updating the icons and colors.

### Finally add the toggle switch inside the component
`App.js`
```
import React, { useContext } from "react";

import { theme } from "./theme";

import { ThemeContext } from "./Provider";
import ThemeSwitch from "./ThemeSwitch";

const getStyles = (mode) => ({
  header: {
    fontSize: 34,
    fontWeight: "400"
  },
  app: {
    height: "100%",
    width: "100%",
    padding: 16,
    backgroundColor: theme[mode].backgroundColor
  },
  text: {
    fontWeight: "200",
    color: theme[mode].color
  },
  theme: {
    color: theme[mode].highlight
  }
});

export default function App() {
  const { mode } = useContext(ThemeContext);
  const styles = getStyles(mode);
  return (
    <div style={styles.app}>
      <h1 style={(styles.header, styles.text)}>Have a nice day... DEV!</h1>
      <h2 style={styles.text}>
        Current theme is <span style={styles.theme}>{mode}</span> mode
      </h2>
      <ThemeSwitch />
    </div>
  );
}

``` 
Added  `<ThemeSwitch />` in `App.js`. Now play with toggle switch to notice the changes.


That's all, you can add this `ThemeSwitch` component any where inside your project to change the theme.

🎉 Tada... We are done... 
 

Thanks 😃 for the read...

Drop a ♥️ if this content is helpful...

Suggestions and doubts are always welcome in the comment section...