How to implement a dark to light mode feature in your React/Sass project

There are various methods to implement a light-weight/darkish theme function in your web site. However how are you going to create a clear answer that shall be straightforward to make use of and keep additional time?

On this article, I’ll present you methods to create a light-weight/darkish theme toggle performance utilizing React and Sass.

I’ve created a demo project primarily based on the favored TV present Rick and Morty. There are a few pages devoted to the principle characters all designed in darkish theme.

I’ll stroll you thru methods to add mild theme kinds, and methods to toggle between the 2 themes. You may then use this mild theme answer in your personal tasks.



Desk of Contents



Conditions

This text assumes you’ve got a fundamental basic data of React, Sass, and the command line.

This demo undertaking is utilizing Yarn, so it is strongly recommended that you just install Yarn.



Set up steps for the Demo App

  1. Clone the undertaking
git clone https://github.com/jdwilkin4/Mild-Darkish-Theme-Starter-Code.git
Enter fullscreen mode

Exit fullscreen mode

  1. cd into the Mild-Darkish-Theme-Starter-Code listing
cd Mild-Darkish-Theme-Starter-Code
Enter fullscreen mode

Exit fullscreen mode

  1. Set up the dependencies
yarn set up
Enter fullscreen mode

Exit fullscreen mode

  1. Begin the native server
yarn begin
Enter fullscreen mode

Exit fullscreen mode

It’s best to see the homepage with two hyperlinks that may lead you to the Rick and Morty pages.



How does the sunshine/darkish theme toggle work?

We shall be making a button the place customers can choose if they like darkish or mild mode, and this button will toggle between the 2 kinds. By default, the preliminary setting shall be for darkish mode.

When the consumer refreshes the web page, their theme desire shall be saved in native storage.



How you can set up the useDarkMode hook

We shall be utilizing an npm package deal known as use-dark-mode which is a customized hook used to implement the toggle performance between mild and darkish mode.

Preserve your server operating, open up a brand new tab within the terminal, and run the command yarn add use-dark-mode.



Making a customized useTheme hook

The aim of this hook is to return a string worth of both light-mode or dark-mode primarily based on the present mode we’re in. We’ll then use this string worth as a category and apply it to the JSX parts.

Open up your code editor, find the src folder and create a brand new folder known as utils. Contained in the utils folder, create a brand new file known as useTheme.js.

On the high of your useTheme.js file, embody the React and useDarkMode imports.

import React from "react";
import useDarkMode from "use-dark-mode";
Enter fullscreen mode

Exit fullscreen mode

Beneath these imports, add these two variables:

const lightTheme = "light-mode";
const darkTheme = "dark-mode";
Enter fullscreen mode

Exit fullscreen mode

Beneath the variable declarations, you’ll create the useTheme hook.

export const useTheme = () => {};
Enter fullscreen mode

Exit fullscreen mode

Contained in the useTheme hook, we wish to embody the useDarkMode hook and assign it to a const variable known as darkMode.

const darkMode = useDarkMode();
Enter fullscreen mode

Exit fullscreen mode

The return worth for the useDarkMode() hook is an object, and one of many property names we’re going to use is known as worth. The worth property is a boolean which represents if darkish mode is on or not.

Subsequent, we wish to add a brand new state variable and assign it the darkish theme worth.

const [theme, setTheme] = React.useState(darkTheme);
Enter fullscreen mode

Exit fullscreen mode

We’re then going so as to add a useEffect hook and replace the theme primarily based on every time the mode adjustments.

React.useEffect(() => {
  setTheme(darkMode?.worth ? darkTheme : lightTheme);
}, [darkMode.value]);
Enter fullscreen mode

Exit fullscreen mode

We’re including darkMode.worth to the dependency array as a result of we wish it to solely re-run the impact when the worth adjustments on re-render.

Lastly, we wish to return our theme.

return theme;
Enter fullscreen mode

Exit fullscreen mode

That is what the complete useTheme hook ought to appear to be.

export const useTheme = () => {
  const darkMode = useDarkMode();
  const [theme, setTheme] = React.useState(darkTheme);
  React.useEffect(() => {
    setTheme(darkMode?.worth ? darkTheme : lightTheme);
  }, [darkMode.value]);

  return theme;
};
Enter fullscreen mode

Exit fullscreen mode



Creating the sunshine/darkish theme toggle button

Find the src/parts folder, and create a file ThemeBtn.js and a ThemeBtn.scss file.

Inside that file, add the imports for React, useDarkMode and useTheme.

import React from "react";
import useDarkMode from "use-dark-mode";
import { useTheme } from "../utils/useTheme";
Enter fullscreen mode

Exit fullscreen mode

Proper beneath these imports, embody your stylesheet for this button part.

import "../parts/ThemeBtn.scss";
Enter fullscreen mode

Exit fullscreen mode

Now, we’re going to create our Button part.

const ThemeBtn = () => {};
export default ThemeBtn;
Enter fullscreen mode

Exit fullscreen mode

Contained in the ThemeBtn part, we’re going to use the useDarkMode hook and set the worth to true as a result of we wish the default to be set to darkish mode.

const darkMode = useDarkMode(true);
Enter fullscreen mode

Exit fullscreen mode

We’re additionally going to create a variable known as theme and assign to it the useTheme hook.

const theme = useTheme();
Enter fullscreen mode

Exit fullscreen mode

Contained in the return, we’re going to create a button. Since darkMode is an object that has a property known as toggle, we are able to use that within the onClick operate to toggle between mild and darkish themes.

For the button textual content, we’ll create a ternary operator which is able to present the textual content of “Mild mode” or “Darkish mode” relying on the state of the theme.

return (
  <button className="btn-theme" sort="button" onClick={darkMode.toggle}>
    {theme === "dark-mode" ? "Mild mode" : "Darkish mode"}
  </button>
);
Enter fullscreen mode

Exit fullscreen mode

In an effort to see our toggle button in motion, we have to add it to one of many pages. Most individuals select so as to add the toggle button to the navigation bar. For our demo undertaking, we’ll add it to the App.js file.

Import the ThemeBtn into the App part, and add the <ThemeBtn /> simply earlier than the routes.

import ThemeBtn from "./parts/ThemeBtn";
operate App() {
  return (
    <>
      <ThemeBtn />
      <Routes>
        <Route path="/" ingredient={<Homepage />} />
        <Route path="/rick" ingredient={<RickSanchezPage />} />
        <Route path="/morty" ingredient={<MortySmithPage />} />
      </Routes>
    </>
  );
}
Enter fullscreen mode

Exit fullscreen mode

It’s best to now see the button within the browser. Attempt clicking on it and see the textual content change between mild and darkish mode.

light dark mode button

Let’s add some styling to our button.

Open up the ThemeBtn.scss file and add these kinds for the btn-theme class.

@import "../kinds/colours";

.btn-theme {
  background-color: $purple100;
  border: none;
  shade: $grey100;
  show: block;
  font-size: 1.2rem;
  font-weight: 600;
  width: 150px;
  padding: 5px;
  text-align: heart;
  margin: 0;
  cursor: pointer;

  &:hover {
    background-color: $purple200;
  }
}
Enter fullscreen mode

Exit fullscreen mode



Including the useTheme hook to all of the pages

We have to import the useTheme hook to all of our pages as a result of we wish to apply the darkish and lightweight mode courses to the JSX parts.

Contained in the App.js file, import the useTheme hook.

import { useTheme } from "./utils/useTheme";
Enter fullscreen mode

Exit fullscreen mode

Contained in the App part, create a variable known as theme, and assign the hook to it.

const theme = useTheme();
Enter fullscreen mode

Exit fullscreen mode

Exchange the empty React fragments with div parts, and apply the theme variable to the className.

<div className={theme}>
  <ThemeBtn />
  <Routes>
    <Route path="/" ingredient={<Homepage />} />
    <Route path="/rick" ingredient={<RickSanchezPage />} />
    <Route path="/morty" ingredient={<MortySmithPage />} />
  </Routes>
</div>
Enter fullscreen mode

Exit fullscreen mode

For the Button.js file, import the useTheme hook, and create the theme variable like earlier than. Then, add that variable to the className.

import { useTheme } from "../utils/useTheme";

export const Button = ({ textual content, path }) => {
  const theme = useTheme();
  return (
    <Hyperlink to={path} className={`btn ${theme}`}>
      {textual content}
    </Hyperlink>
  );
};
Enter fullscreen mode

Exit fullscreen mode

For the CharacterTemplate.js file, import the useTheme hook and create the theme variable like earlier than. Then add that variable to the className for the div parts.

// right here is the total JSX markup
<div className={theme}>
  <h1>{title}</h1>
  <Button textual content="Return House" path="/" />
  <div className="flex-container">
    {characterInfo.map((character, id) => (
      <div key={id} className="character-container">
        <h2>{character.title}</h2>
        <img src={character.picture} alt="character avatar" />
      </div>
    ))}
  </div>
</div>
Enter fullscreen mode

Exit fullscreen mode



How you can add a Sass map for the sunshine/darkish theme kinds

Contained in the kinds folder, open up the colours file and add the $grey200: #f5f1f1; variable.

That is what the whole colours file ought to appear to be.

$blue700: #1a1a40;
$blue600: #2c2c66;
$black: #000;
$grey100: #fdfcfc;
$grey200: #f5f1f1;
$purple100: #7a0bc0;
$purple200: #650c9d;
Enter fullscreen mode

Exit fullscreen mode

Contained in the kinds folder, create a brand new file known as _light-dark-theme.scss.

On the high of your Sass file, import the colours file.

@import "./colours";
Enter fullscreen mode

Exit fullscreen mode

Then, we’re going to create a brand new Sass map known as themes.

$themes: ();
Enter fullscreen mode

Exit fullscreen mode

Contained in the themes map, we’re going to add particular person maps for the background and textual content colours used for the sunshine and darkish themes.

$themes: (
  bgThemeColor1: (
    darkTheme: $blue700,
    lightTheme: $grey100
  ),
  bgThemeColor2: (
    darkTheme: $blue600,
    lightTheme: $grey200
  ),
  textThemeColor1: (
    darkTheme: $grey100,
    lightTheme: $black
  )
);
Enter fullscreen mode

Exit fullscreen mode

We are actually going to create a mixin known as kinds with an argument known as $mode. This mixin shall be used afterward within the dark-mode and light-modecourses.

@mixin kinds($mode) {
}
Enter fullscreen mode

Exit fullscreen mode

Contained in the mixin, we’re going to create an @every rule that may iterate by means of every key worth pair within the themes map.

@every $key, $map in $themes {
}
Enter fullscreen mode

Exit fullscreen mode

The $key represents every of the background and textual content colours we created (Ex. bgThemeColor1). The $map represents every of the values.
For instance:

  (
    darkTheme: $blue700,
    lightTheme: $grey100,
  )
Enter fullscreen mode

Exit fullscreen mode

Inside that @every rule, we’re going to create one other rule that iterates over every key/worth pair for the person maps.

@every $prop, $shade in $map {
}
Enter fullscreen mode

Exit fullscreen mode

Inside that @every rule, we’ll create a situation that checks which mode we’re in and applies the suitable model to that class.

@if $prop == $mode {
  --#{$key}: #{$shade};
}
Enter fullscreen mode

Exit fullscreen mode

The rationale why we’re including the -- in entrance of the important thing, is as a result of we wish to reference these shade variables within the particular person stylesheets utilizing CSS variable syntax.

For instance:

var(--color)
Enter fullscreen mode

Exit fullscreen mode

That is what the whole mixin ought to appear to be.

@mixin kinds($mode) {
  @every $key, $map in $themes {
    @every $prop, $shade in $map {
      @if $prop == $mode {
        --#{$key}: #{$shade};
      }
    }
  }
}
Enter fullscreen mode

Exit fullscreen mode

Beneath the mixin, we’re going to add the sunshine and darkish theme kinds to the suitable courses utilizing the @embody rule.

.dark-mode {
  @embody kinds("darkTheme");
}

.light-mode {
  @embody kinds("lightTheme");
}
Enter fullscreen mode

Exit fullscreen mode

That is what the complete light-dark-theme file ought to appear to be.

@import "src/kinds/colours";

$themes: (
  bgThemeColor1: (
    darkTheme: $blue700,
    lightTheme: $grey100,
  ),
  bgThemeColor2: (
    darkTheme: $blue600,
    lightTheme: $grey200,
  ),
  textThemeColor1: (
    darkTheme: $grey100,
    lightTheme: $black,
  ),
);

@mixin kinds($mode) {
  @every $key, $map in $themes {
    @every $prop, $shade in $map {
      @if $prop == $mode {
        --#{$key}: #{$shade};
      }
    }
  }
}

.dark-mode {
  @embody kinds("darkTheme");
}

.light-mode {
  @embody kinds("lightTheme");
}
Enter fullscreen mode

Exit fullscreen mode



Making use of the themes to the person stylesheets

Contained in the App.scss file, import the light-dark-theme file.

@import "./kinds/light-dark-theme";
Enter fullscreen mode

Exit fullscreen mode

We’re going to change the background and textual content colours with the variables we created earlier.

physique {
  background-color: var(--bgThemeColor1);
  shade: var(--textThemeColor1);
  text-align: heart;
}
Enter fullscreen mode

Exit fullscreen mode

Should you take a look at out the sunshine/darkish theme toggle button, you’ll discover that the background and textual content colours will change.

It could be good if there have been a gradual transition between the 2 colours. We will accomplish this through the use of the CSS transition property.

physique {
  background-color: var(--bgThemeColor1);
  shade: var(--textThemeColor1);
  text-align: heart;
  transition: background-color 0.5s ease;
}
Enter fullscreen mode

Exit fullscreen mode

Contained in the CharacterTemplate.scss file, import the light-dark-theme file.

@import "../kinds/light-dark-theme";
Enter fullscreen mode

Exit fullscreen mode

Then change the background and textual content colours with the CSS variables we created earlier.

  .character-container {
    shade: var(--textThemeColor1);
    background-color: var(--bgThemeColor2);
Enter fullscreen mode

Exit fullscreen mode

Go to the browser and take a look at out the sunshine/darkish theme button. It’s best to be capable of see each themes.

morty page



Conclusion

Now we have efficiently created a light-weight/darkish theme answer utilizing React and Sass.

You may implement this answer into your personal tasks and will probably be straightforward to scale and keep over time.

Right here is the final demo project and source code.


This Dot Labs is a contemporary net consultancy centered on serving to firms notice their digital transformation efforts. For professional architectural steering, coaching, or consulting in React, Angular, Vue, Net Parts, GraphQL, Node, Bazel, or Polymer, go to thisdot.co

Add a Comment

Your email address will not be published. Required fields are marked *