HomeTutorsContact

How to create simple theme switcher in CSS and JavaScript?

By Gulshan Saini
Published in HTML
June 07, 2020
2 min read

In this tutorial we are going to learn how to create switch between dark and light theme using vanilla JavaScript and CSS. We will also be using browser localStorage to persist the theme.

So let’s get started with below HTML and CSS.

<html>
  <head>
    <title>Light / Dark Theme Switcher in Vanilla JavaScript and CSS</title>
  </head>

  <body>
    <header>
      <div class="logo">Brand</div>
      <nav>
        <ul>
          <li><a href="#home">Home</a></li>
          <li><a href="#news">News</a></li>
          <li><a href="#contact">Contact</a></li>
          <li><a href="#about">About</a></li>
        </ul>
      </nav>
      <button id="theme">Dark</button>
    </header>
    <main>
      <h1>Chocolate Chip Muffins</h1>
      <p>
        A muffin is an individual-sized, baked product. It can refer to two
        distinct items, a part-raised flatbread that is baked and then cooked on
        a griddle (typically unsweetened) and a cupcake-like quickbread (often
        sweetened) that is chemically leavened and then baked in a mold. While
        quickbread muffins are often sweetened, there are savory varieties made
        with ingredients such as corn and cheese. The flatbread is of British or
        European derivation, and dates from at least the early 18th century,
        while the quickbread originated in North America during the 19th
        century. Both are common worldwide today.
      </p>
      <h2>Muffin top</h2>
      <p>
        The muffin top is the crisp upper part of the muffin, which has
        developed a "browned crust that's slightly singed around the edges". In
        2018, McDonald's restaurant announced they were planning to sell muffin
        tops as part of its McCafe breakfast menu.
      </p>
    </main>
  </body>
</html>

and following CSS

* {
  margin: 0;
  padding: 0;
}

:root {
  --font: Sans-Serif;
  --font-size-1: 16px;
  --font-size-2: 32px;
  --font-size-3: 48px;
  --font-size-4: 56px;
  --font-weight-1: 400;
  --font-weight-2: 700;
  --font-weight-3: 900;
  --white: white;
  --black: black;
}

body {
  font-family: var(--font);
  font-size: var(--font-size-1);
  max-width: 960px;
  margin: 0 auto;
}

header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

header .logo {
  font-size: var(--font-size-2);
  font-weight: var(--font-weight-2);
}

nav ul {
  list-style-type: none;
  display: flex;
}

nav ul li {
  margin-right: 10px;
}

header #theme {
  border: 0;
  padding: 5px 10px;
}

h1,
h2 {
  margin-top: 30px;
  margin-bottom: 10px;
}

h1 {
  font-size: var(--font-size-4);
}

h2 {
  font-size: var(--font-size-3);
}

If you save, above markup in a file and load in browser you should see below output. Please make sure you load the page using a local server.

css theme switcher output 1
css theme switcher output 1

Let’s give theme switcher button life that is located on top-right corner.

Step 1

Set a data-theme attribute on body element as follows

<body data-theme=""></body>

We have not set any value to data-theme attribute and will treat default/null is equal to light theme.

So if you save it and reload the browser tab you won’t see any difference.

Step 2

Next, we will set onclick handler of theme swicther button

<button id="theme" onclick="switchTheme()">Dark</button>

Now we have defined the onclick handler however we have not created the function yet. So lets create switchTheme() function. You can open the script tags within document or create the function in separate file.

Before we author that function lets gather our requirements

  • get current theme value from localStorage theme property - on inital load this won’t exist so, it will return null. We are using localStorage as we need to persist the theme betwen various page loads. If current theme is light update the theme value to dark or vice-versa.
  • next, we need to update the theme value in localStorage theme variable.
  • finally, we can set the new theme value on data-theme attribute defined in step#1 above
function switchTheme() {
  // toggle theme
  const toggleValue =
    localStorage.getItem('theme') === 'dark' ? 'light' : 'dark'

  // update localstorage value;
  localStorage.setItem('theme', toggleValue)

  // set current theme - default to `light` on first load and set `theme` property in localStorage.
  const currentTheme = localStorage.getItem('theme') || 'light'

  // update current theme value on `data-theme` attribute
  document.body.dataset.theme = currentTheme
}

Step 3

So, our switchTheme() function is ready. Now, we need to handle the scenario when the website is loaded the first time - again there are two cases here listed below

  • a user could be new on the website for whom the theme was never set
  • a user could be returning user for whom we need to load theme based on his past preference.

So let’s handle the above two scenarios in function setTheme() and here are our detailed requirements

  • get the current theme from localStorage and if the property theme is not found then default it to light on the first load
  • update current theme value on data-theme attribute that we created in step#1 above.
  • update the inner text of the button dynamically based on the current theme.
  • call the setTheme() function on initial page load
const themeSwitcher = document.querySelector('#theme')

function setTheme() {
  // set current theme - default to `light` on first load and set `theme` property in localStorage.
  const currentTheme = localStorage.getItem('theme') || 'light'

  // update current theme value on `data-theme` attribute
  document.body.dataset.theme = currentTheme

  // update inner text of button dynamically based on current theme
  themeSwitcher.innerText = currentTheme === 'light' ? 'Dark' : 'Light'
}

// set theme on inital load
setTheme()

Step 4

As you can see few of steps are common between the switchTheme() function and setTheme() function so, its good time to refactor switchTheme() function and below is updated code.

We have removed last 2 lines and called setTheme() function instead

function switchTheme() {
  // toggle theme
  const toggleValue =
    localStorage.getItem('theme') === 'dark' ? 'light' : 'dark'

  // update localstorage value;
  localStorage.setItem('theme', toggleValue)

  // update theme
  setTheme()
}

We have covered the JavaScript part here. Now if you open the developer console and go to the Application tab, Local Storage section and then click on the theme switcher button you should see the theme being updated at each click.

css theme switcher output 2
css theme switcher output 2

Step 5

Now we just need to add magic of CSS data attributes here to respond to theme switcher button.

[data-theme='dark'],
[data-theme='dark'] a {
  color: var(--white);
  background: var(--black);
}

[data-theme='light'] #theme {
  color: var(--white);
  background: var(--black);
}

You can use any color however, I just used two colors i.e. white and black.

Logic

  • When the data-theme is set to dark, we are setting the font color to white and background color to black. No action is required when the theme color is light as the browser will default the font color to black and background color to white.
  • Next, we just need to handle the theme switcher button background color and font so that it is visible both in; light and dark modes.

Example

A working demo of code discussed above


Tags

#css
Previous Article
How to use CSS custom variables and properties?

Related Posts

HTML
How to detect color preference based on user settings?
June 08, 2020
1 min
Gulshan Saini

Gulshan Saini

Fullstack Developer

Topics

Angular
JavaScript
Typescript
ReactJS

Subscribe to our newsletter!

We'll send you the best of our blog just once a month. We promise.
© 2021, All Rights Reserved.

Quick Links

Contact UsBrowserCSSPythonPuppeteer

Social Media