DEV Community

Cover image for Implement dark mode in React πŸŒžπŸŒ•
Suryaraj Bhaduri
Suryaraj Bhaduri

Posted on

Implement dark mode in React πŸŒžπŸŒ•

Who doesn't want a dark theme on their website! Not only does it help us focus better, but also keeps our eyes safer πŸ€“.

The blog might add value if you belong to either of these situations -

  • Maybe you have been in a place wherein you want to implement a dark theme for your website but are struggling around the same 😡.

  • You are starting out with React, so this might just be another fun exercise for you to try πŸŽ‰.

Prerequisites

  • Basic knowledge of React and terminologies (state, props, etc.)
  • Basic knowledge of CSS
  • Will to learn πŸš€

Spin up a new React Project ✨

You could use your local development environment or maybe use a sandbox.

NoteπŸ“ - If using local setup prefer cleaning up the factory code before moving further.

Also, I will be using class based components for this one - not using React Hooks.

Create a simple page

In our App(), just return a div for the time being. (Can use a button as well)

Init setup

Add state to our app

We cannot do much with a dumb component when it comes to embedding logic inside of it. So we need to add state to the React component.

Add a state called isDarkThemeEnabled to the App component and set it to false.
Adding state

Creating the theme switcher logic πŸ’‘

This is the crux of the entire problem.

How to build the theme switcher / toggler ?

This might become simple, if you try to draw an analogy to a light bulb. A light bulb has two states on and off.
At any given point of time it is in one of the either states.

Now, imagine the theme switcher to be a bulb and try to map the idea.

You got it! πŸŽ‰ If the theme switcher is imagined to be a light bulb, light mode becomes on and dark mode becomes off or vice-versa.

Now, how to toggle the state ? Pretty simple, just flip the current state whenever a certain event fires.
In simpler terms - on clicking a button change the state value from true to false or vice versa.

Implementing the theme switcher logic

Now, as we have designed the approach it's good time to start coding up the idea.
FYI for changing state in React we use the setState function. You can read about the setState API from here.

Let's create a clickHandler and embed the state-toggler logic inside of it.
Click handler

Pass this clickHandler to the onClick prop of the div, to trigger the function whenever user clicks on the div.

clickHandler passed to prop

Adding SVG to our app

I want to let the user know which mode he can currently switch to. Can be accomplished with text, but what better than using SVG icons to enhance the UI !πŸŽ‰

I will be using heroicons for high quality SVG icons.

Create two files in your /src directory, for two SVG icons for the two states. I will be using a Moon and a Sun SVG in this case.

folder structure

To use any SVG in our React app, we can directly use them in our code or import the SVG as a React Component. I prefer the latter as it helps to keep the code cleaner.

This is how we import an SVG icon as a React component -

import {ReactComponent as Moon} from './moon.svg';
Enter fullscreen mode Exit fullscreen mode

We need to toggle the SVG icons as well to suit our purpose. For this we will use conditional rendering.
This is a gem πŸ’Ž. You can read about this here.

The idea is, whenever isDarkThemeEnabled is true we need the sun SVG to show up else the moon SVG should show up.

conditional render

This is how the app looks right now. You're almost there.🏁
demo GIF

Let's style up our app

When dark mode is enabled we would want to paint our app background dark. So, for this we would prefer applying classNames conditionally.
You can read on this from here.

We would be using JSX expression and Template Literals for this. When isDarkThemeEnabled is set to true, which means dark mode is enabled, we would append a className to the App className.

className={`App ${isDarkThemeEnabled && "dark-mode"}`}
Enter fullscreen mode Exit fullscreen mode

Now lets add some style for the .App.dark-mode class.

CSS for App

Let's also style up the SVG icons πŸ’…. Add a className of moon and sun to <Moon /> and <Sun /> components respectively.

This is how the App code looks right now.

import "./styles.css";
import React from "react";
import { ReactComponent as Moon } from "./moon.svg";
import { ReactComponent as Sun } from "./sun.svg";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isDarkThemeEnabled: false,
    };
  }

  handleClick = () => {
    const { isDarkThemeEnabled } = this.state;
    this.setState({
      isDarkThemeEnabled: !isDarkThemeEnabled,
    });
  };

  render() {
    const { isDarkThemeEnabled } = this.state;
    return (
      <div className={`App ${isDarkThemeEnabled && "dark-mode"}`}>
        <div className="toggler-btn" onClick={this.handleClick}>
          {isDarkThemeEnabled ? (
            <Sun className="sun" />
          ) : (
            <Moon className="moon" />
          )}
        </div>
      </div>
    );
  }
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Add desired styles in the styles.css.
styles

✨ Add a transition time to the wrapper class to make the color switch smoother. I added transition: 0.3s ease to .App.

This is how the App looks finally!
Note - I have added some additional styles and animations.

For a larger websites use css variables to make painting UI components on theme toggle easier.

Feel free to play around with the sandbox.

Conclusion

Congratulations!! πŸŽ‰πŸŽ‰ You made it till the end. If you're still here chances are you probably liked the blog.

You can also make improvisations to this simple project and share them. This would help in getting the fundamentals stronger πŸ‹ πŸš€.

Do let me know how you liked the blog and where I need to improve. Would be eagerly waiting for feedback!

Latest comments (6)

Collapse
 
lostigeros profile image
Patryk L. • Edited

Shouldn't you use setState with a snapshot of previous state? It should not be directly mutated.

this.setState((prevState) => ({
  isDarkThemeEnabled: !prevState.isDarkThemeEnabled
}));
Enter fullscreen mode Exit fullscreen mode
Collapse
 
suryaraj1 profile image
Suryaraj Bhaduri • Edited

True that! Thanks for this.

Collapse
 
talorlanczyk profile image
TalOrlanczyk

Why not to use params and just change it and it will effect all your code

Collapse
 
suryaraj1 profile image
Suryaraj Bhaduri

Didn't think of this idea! Will surely try this out.

Collapse
 
maqi1520 profile image
Alex Ma

Great!
I also wrote an article about how to implement it in the old project Using the PostCSS plugin Let your WebApp support dark mode

Collapse
 
suryaraj1 profile image
Suryaraj Bhaduri

Thanks a lot! πŸŽ‰ Your article looks awesome!