How to Implement Dark Mode with CSS and JavaScript

How to Implement Dark Mode with CSS and JavaScript


About the author

Telmo Goncalves is a software engineer with over 13 years of software development experience and an expert in React. He’s currently Engineering Team Lead at Marley Spoon.

Check out more of his work on telmo.is


images/how-to-implement-dark-mode-with-css-and-js.jpg

I’ve implemented dark/light mode before using styled-components as well as SCSS, but much of the same functionality can be accomplished just using CSS and a bit of JavaScript.

In this article, I’ll provide a step-by-step guide on how to accomplish this for your own application.

This article assumes the reader has minimal knowledge of HTML, CSS, and working with the command line. For more experienced developers, feel free to skip through to select information as needed.


The CSS

First, create a project with a style.css file at the root.

This can be done by running the following in the command line:

mkdir light-dark-mode && touch light-dark-mode/style.css

This creates a new directory, called light-dark-mode, for the project and adds a style.css file to it.

Navigate to the directory by running:

cd light-dark-mode

In the style.css file, add the following code for a default, (light) theme:

:root {
  --background-color: #fff;
  --text-color: #000;
}

To see it working, create an HTML file by running:

touch index.html

And adding the following HTML. Notice the style.css file is imported:

<!DOCTYPE html>
<html>
  <head>
    <title>Light and Dark Mode</title>
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>

  <body>
    <h1>Adding light / dark themes</h1>
  </body>
</html>

Opening the index.html file in a browser should display the header text: Adding light / dark themes"

Now we can add some styling. It’s best practice to use variables, denoted as var(--variable-name), wherever possible. This allows for easy re-use and more descriptive code.

In the style.css file, add:

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

The page should look exactly the same. That’s because we’re using the style declarations in the :root pseudo-class.

Now that the scaffolding for the default (light) theme is set up, variables for the dark mode theme can be added.

Add the following to style.css above the body declaration:

[data-theme="dark"] {
  --background-color: #3F3F3F;
  --text-color: #fff;
}

Notice that it’s similiar to the :root declaration, except the text color is white and the background color is a dark gray.

So far we’ve set up the project so that:

  • The [data-theme="dark"] theme can be toggled on/off (we’ll cover how to do this in the section below).
  • The default appearance will be the light theme. This is why the theme is configured to the :root class and not a separate [data-theme="light"] class.

The JavaScript

Now we can verify the page can adopt the dark mode theme. In the index.html file, add the following JavaScript snippet inside the <head> section:

<script type="text/javascript">
  // Wait for document to load
  document.addEventListener("DOMContentLoaded", function(event) {
    document.documentElement.setAttribute("data-theme", "dark");
  });
</script>

Opening the index.html page in the browser should now reveal a #3F3F3F (dark) background and #fff (white) text.

What does this do?

document.documentElement returns the root Element of the document. So, even without the JavaScript snippet, the dark mode could always be applied if the following were applied:

<!DOCTYPE html>
<html data-theme="dark">

<!-- The rest of the code -->

But because the goal is to allow the user to toggle between the light and dark mode themes, JavaScript is required to handle the changing of state.


The Switch

Next, add a button to index.html that will trigger the theme change.

Inside the <head> section, modify the JavaScript snippet to the following:

<script type="text/javascript">
  // Wait for document to load
  document.addEventListener("DOMContentLoaded", function(event) {
    document.documentElement.setAttribute("data-theme", "light");

    // Get our button switcher
    var themeSwitcher = document.getElementById("theme-switcher");

    // When our button gets clicked
    themeSwitcher.onclick = function() {
      // Get the current selected theme, on the first run
      // it should be `light`
      var currentTheme = document.documentElement.getAttribute("data-theme");

      // Switch between `dark` and `light`
      var switchToTheme = currentTheme === "dark" ? "light" : "dark"

      // Set our currenet theme to the new one
      document.documentElement.setAttribute("data-theme", switchToTheme);
    }
  });
</script>

And add a <button> to the <body> section:

<button id="theme-switcher">Switch themes!</button>

What this does is:

  • Creates a button element that’s visible on the page.
  • Creates a function so that the theme is changed to dark mode when it’s clicked,
  • And back to light if it’s clicked again.

That’s it! Reload index.html in the browser and try it out.


Telmo regularly posts helpful React development tips and guides on Twitter. Be sure to follow him at @telmo


About PullRequest

HackerOne PullRequest is a platform for code review, built for teams of all sizes. We have a network of expert engineers enhanced by AI, to help you ship secure code, faster.

Learn more about PullRequest

Telmo Goncalves headshot
by Telmo Goncalves

October 22, 2020