An interactive tutorial to implement a dark mode on any website.

An interactive tutorial to implement a dark mode on any website.

Written by Pranav Chakkarwar on 02 Jun 2021 • 12 minutes to read

Adding a dark mode to any website is a great way to make it more visually appealing. It also makes the website more accessible. This article will guide you to add a toggle switch for dark theme on any website. Read till the end to avoid missing any important details. If I miss something relevant, please let me know in the comments section.

Take a look at a recorded demo!

gif demo of theme testing

The first technique is to use a button to activate and deactivate the dark mode.

Click the lightning bolt to try it out.



Hello, here's some text to demonstrate changing of styles using a toggle. Your preference will be saved in the browser's local storage as well. To test it, try refreshing the page.

To modify the colors of the text, background, and svg fill, we’ll use CSS variables.

.init {
  background: #ffffff !important;
  color: #000000 !important;
  --lightboltsvg: #fff348 !important;
  transition-duration: 0.5s;
}

body {
  background: #000000;
  color: #ffffff;
  padding: 3rem;
  border-radius: 0.25rem;
  --lightboltsvg: #505050;
  text-align: center;
  transition-duration: 0.5s;
}

In the html, make sure the element with the id #toggle-button is inside the element with the id #themebuttondiv.

<body id="themebuttondiv" class="themebuttondiv init">
  <div id="toggle-btn">
    <svg
      id="lightboltsvg"
      height="50"
      width="50"
      fill="var(--lightboltsvg)"
      viewBox="0 0 512 512"
    >
      <g>
        <g>
          <polygon
            points="426.667,213.333 288.36,213.333 333.706,0 148.817,0 85.333,298.667 227.556,298.667 227.556,512 		"
          />
        </g>
      </g>
    </svg>
  </div>
  <br /><br />
Hello, here's some text to demonstrate changing of styles using a toggle.
Your preference will be saved in the browser's local storage as well.
To test it, try refreshing the page. 
</body>

Coming to JavaScript, we’ll first define some constants in JavaScript.

const themetoggleexample = document.getElementById("toggle-btn");
themediv = document.getElementById("themebuttondiv");
const themetogglestore = localStorage.getItem("themetoggleexample");

To detect the preferred theme on each page load, we’ll use the browser’s local storage API to save an user’s preference locally. This will come in handy if an user navigates to another page.

A simple if statement will get the job done.

if (themetogglestore) {
  themediv.classList.remove("init");
}

The page will load initially with a light theme set by the init class. Whenver an user changes their theme, we need to check if the init class is present in the body tag. If it does, we’ll remove it and save the choice by storing a value in the local storage of the browser.

If an user decides to change the theme again, the if statement will render false but the else statement will restore the init class back to the body tag and delete the custom preference from the browser’s local storage.

themetoggleexample.onclick = () => {
  if (themediv.classList.contains("init")) {
    themediv.classList.remove("init");
    localStorage.setItem("themetoggleexample", "theme-dark");
  } else {
    themediv.classList.add("init");
    localStorage.removeItem("themetoggleexample");
  }
};

The complete javascript is quite easy to understand.

const themetoggleexample = document.getElementById("toggle-btn");
themediv = document.getElementById("themebuttondiv");
const themetogglestore = localStorage.getItem("themetoggleexample");

if (themetogglestore) {
  themediv.classList.remove("init");
}

themetoggleexample.onclick = () => {
  if (themediv.classList.contains("init")) {
    themediv.classList.remove("init");
    localStorage.setItem("themetoggleexample", "theme-dark");
  } else {
    themediv.classList.add("init");
    localStorage.removeItem("themetoggleexample");
  }
};

Another technique is to automatically adjust to an user’s preference.

We’ll use simple CSS Media Queries to identify an user’s preference from the browser’s settings.

Hello, here's some text to demonstrate the use of CSS media queries. To see the style update, change your theme configuration. No reload requried :)

Test it using the Firefox inspect mode.

find the toggle in Firefox inspect mode

For Chromium-based browsers, it’s a two-step process.

find the toggle in chrome step one

find the toggle in chrome step two

The CSS is quite straightforward and does not require any JavaScript.

:root {
      background: white;
      color: black;
    }

    @media (prefers-color-scheme: dark) {
    :root {
      background: black;
      color: white;
    }
  }
}

If you don’t need to give users a choice specific to your website, this method is ideal.

We can combine multiple approaches to make the design user-friendly.

To showcase the use of multiple approaches, I’ll take the example of an user with JavaScript turned off.

We’ll utilize the noscript html tag to check if JavaScript is turned off and use CSS media queries to determine an user’s preference from the browser’s settings. Cool! isn’t it?

<noscript>
  <style>
    .init {
      background: #ffffff !important;
      color: #000000 !important;
      --lightboltsvg: #fff348 !important;
    }
    @media (prefers-color-scheme: dark) {
      .init {
        background: #000000 !important;
        color: #ffffff !important;
        --lightboltsvg: #505050 !important;
      }
    }
  </style>
</noscript>

Taking it further with the dark mode.

We can geolocate an user or might use the user’s browser time to define a preference seamlessly and apply the theme. The JavaScript for detecting the time zone might look like…

var date = new Date();
var offset = date.getTimezoneOffset();
console.log(offset);

These approaches, however, may come with a number of drawbacks.

If you can think of any other technique, please share them in the comments section. Thank you for having a read at this :)

The whole code is given below. It may not be pristine, but it is certainly usable.

<body id="themebuttondiv" class="themebuttondiv init">
  <style>
    .init {
      background: #ffffff !important;
      color: #000000 !important;
      --lightboltsvg: #fff348 !important;
    }

    body {
      background: #000000;
      color: #ffffff;
      padding: 3rem;
      border-radius: 0.25rem;
      --lightboltsvg: #505050;
      text-align: center;
    }
  </style>

  <div id="toggle-btn">
    <svg
      id="lightboltsvg"
      height="50"
      width="50"
      fill="var(--lightboltsvg)"
      viewBox="0 0 512 512"
    >
      <g>
        <g>
          <polygon
            points="426.667,213.333 288.36,213.333 333.706,0 148.817,0 85.333,298.667 227.556,298.667 227.556,512"
          />
        </g>
      </g>
    </svg>
  </div>
  <br /><br />
  Hello, here's some text to demonstrate changing of styles using a toggle. Your
  preference will be saved in the browser's local storage as well. To test it,
  try refreshing the page.
  <br /><br /><br />
  Also, try disabling script and change your theme preference through the
  browser to see the magic!

  <script>
    const themetoggleexample = document.getElementById("toggle-btn");
    themediv = document.getElementById("themebuttondiv");
    const themetogglestore = localStorage.getItem("themetoggleexample");

    if (themetogglestore) {
      themediv.classList.remove("init");
    }

    themetoggleexample.onclick = () => {
      if (themediv.classList.contains("init")) {
        themediv.classList.remove("init");
        localStorage.setItem("themetoggleexample", "theme-dark");
      } else {
        themediv.classList.add("init");
        localStorage.removeItem("themetoggleexample");
      }
    };
  </script>

  <noscript>
    <style>
      .init {
        background: #ffffff !important;
        color: #000000 !important;
        --lightboltsvg: #fff348 !important;
      }
      @media (prefers-color-scheme: dark) {
        .init {
          background: #000000 !important;
          color: #ffffff !important;
          --lightboltsvg: #505050 !important;
        }
      }
    </style></noscript
  >
</body>


Enjoyed this article?


Comments

Post a comment

Comments will be manually approved and will take time to reflect.

You may also Enjoy

Crafting a minimal, fast and yet a feature-rich blog (Introduction)

Crafting a minimal, fast and yet a feature-rich blog (Introduction)

Published on 24 Nov 2021 • 5 minutes to read

Build your identity on the internet using a blog and share your ideas. The internet is open and w...
A personal dashboard with bookmarks and search that works across browsers.

Crossbrowser personal dashboard

Published on 05 Jun 2021 • 1 minutes to read

A tutorial to setup a personal dashboard with bookmarks and search that works across browsers. No...
How to self host a Privacy respecting analytics solution?

Self hosted & Privacy friendly analytics

Published on 04 May 2021 • 7 minutes to read

Big tech companies collect more and more data to keep their advertising business model running to...