Easy Dark Theme Toggle in React using local storage

Easy Dark Theme Toggle in React using local storage

Every app/website is now featured with a dark theme. Not only does it look cool but it's also easier on the eyes.

Today we're going to implement the dark mode functionality in our react app. We'll also store the theme preference in the browser's local storage so that next time we visit the app, our theme stays as chosen before.

First of All, let's create our react boilerplate,

npx create-react-app darkmode-example

After that let's inject a button in the App.js

import "./styles.css";

const App = () => {
  return (
    <div>
      <button>toggle theme</button>
    </div>
  );
};

module.exports = App;

To set our theme state, we will use the useState hook.

const [theme, setTheme] = useState("light");

Let's set a handler function for toggling the state of the theme and also assign the function to our button.

import { useEffect, useState } from "react";
import "./styles.css";

const App = () => {
  const [theme, setTheme] = useState("light");

  const handleThemeChange = () => {
    if (theme === "light") {
      setTheme("dark");
    } else {
      setTheme("light");
    }
  };

  return (
    <div className="App">
      <button onClick={handleThemeChange}>Toggle theme</button>
    </div>
  );
};

module.exports = App;

Now clicking on the button toggles the state of the theme successfully. But until now, we haven't done anything to style our app based on the theme state, so let's inject some CSS in ourstyles.css file,

:root {
  --text: #333;
  --bg: #fcfcfc;
}

html[data-theme="dark"] {
  --bg: #111;
  --text: #fcfcfc;
}

body {
  background-color: var(--bg);
  color: var(--text);
}

Now we have to set the data theme of our HTML document based on the theme. For that we can use the useEffect hook and add the theme as a dependency so whenever our theme is changed, we should set the data theme.

import { useEffect, useState } from "react";
import "./styles.css";

const App = () => {
  const [theme, setTheme] = useState("light");

  const handleThemeChange = () => {
    if (theme === "light") {
      setTheme("dark");
    } else {
      setTheme("light");
    }
  };

  useEffect(() => {
    document.documentElement.setAttribute("data-theme", theme);
  }, [theme]);

  return (
    <div className="App">
      <button onClick={handleThemeChange}>toggle theme</button>
    </div>
  );
};

module.exports = App;

Now our dark theme UI works properly. Our next goal is to make the theme persistent, which means we have to store the theme value somewhere. In this project, we will store the theme value in the local storage. Let's add the feature,

import { useEffect, useState } from "react";
import "./styles.css";

const App = () => {
  const [theme, setTheme] = useState(
    JSON.parse(localStorage.getItem("theme")) || "light"
  );

  const handleThemeChange = () => {
    if (theme === "light") {
      setTheme("dark");
    } else {
      setTheme("light");
    }
  };

  useEffect(() => {
    localStorage.setItem("theme", JSON.stringify(theme));
    document.documentElement.setAttribute("data-theme", theme);
  }, [theme]);

  return (
    <div className="App">
      <button onClick={handleThemeChange}>toggle theme</button>
    </div>
  );
};

module.exports = App;

We added two things here,

  • First, when our app starts, it will check whether there is a theme variable available in our local storage, if it exists our styles.css will apply the theme according to that otherwise theme is set to the light theme by default.

  • Secondly, whenever we change the theme, we will store the new theme value to the localstorage.

React_App_-_Google_Chrome_2022-03-03_21-22-36_AdobeCreativeCloudExpress.gif