CSS and JavaScript for website dark mode

How to create a dark mode on a website

a bored fish

Introduction to dark mode

Looking around the web I think perhaps that it is only web developers who are obsessed with a dark mode for their websites and apps. For example, there is no dark mode available on the BBC, New York Times and Washington Post websites. There is on MDN Docs, Vercel, Svelte, React, Vue, Tailwind and Bootstrap websites! So how is a dark mode created with CSS and JavaScript?

HTML for dark mode

On the websites with a dark theme there is a common method. A sun icon to click on is shown in dark mode, whereas a moon icon is displayed in light mode. In this example I downloaded sun and moon icons as .svg files from Bootstrap icons into a project folder called images.

The HTML is quite simply 2 images inside a button:

<button class="darkmode-button">
 <img src="./img/sun.svg" alt="sun icon" class="sun hide">
 <img src="./img/moon.svg" alt="moon icon" class="moon">
 </button>

For accessibility (a11y) reasons each img tag is provided alternative (alt) text and each image are enclosed within HTML button tags.

CSS for dark mode

Notice that the sun icon has a class of ‘hide’. In the CSS file, the .hide class has a display of ‘none’. It is this hide class that will be toggled on a click of the button.

.hide {
 display: none;
}

In this example a light mode is the default, therefore the body CSS is:

body {
 background-color: #f5f5f5;
 color: #333;
}

And a dark theme class is prepared to invert the background and font colors:

body.dark-theme {
 background-color: #333;
 color: #f5f5f5;
}

That’s it for the CSS. Now for a smatter of JavaScript to make things work 👀

JavaScript for dark mode

The beauty of JavaScript is that problems can be solved in a mulitude of ways. Here is how I added the dark mode and light mode interactivty primarily with the sun / moon icon button.

To follow through the code you will also need to refer to the HTML and CSS above. At the beginning of my app.js script file, I created a darkTheme variable without a value and a ui (user interface) object that hooked up the sun and moon image icons with .querySelector.

let darkTheme;

const ui = {
 sun: document.querySelector('.sun'),
 moon: document.querySelector('.moon')
}

At the end of the app.js script file, I added an event listener on the button containing the sun and moon icons. If clicked this button, with a class of darkmode-button, would instantiate the toggleTheme function.

document.querySelector(`.darkmode-button`).addEventListener('click', toggleTheme)

Here is what the page looks like so far. A moon icon to click on!

web page with light theme

JavaScript functions

In my learning of JavaScript I always remember, though do not always practise, that functions should only do one thing. In this example I took this approach.

Dark mode interactivity

Toggle theme

On a click of the button, the toggleTheme function is called. As described it toggles the darkTheme variable from false to true and vice versa. Having perfomed the toggle the browser’s local storage is updated with the user’s preferred darkTheme.

function toggleTheme() {
 darkTheme = !darkTheme;
 localStorage.setItem('usersTheme', JSON.stringify(darkTheme))

 changeColors()
 changeIcons()
}

After the darkTheme has been changed the changeColors and changeIcons functions need to be called.

Add and remove dark theme

The changeColors function uses a ternary operator to add or remove the dark-theme from the document body.

function changeColors() {
 darkTheme ?
 document.body.classList.add('dark-theme') : 
 document.body.classList.remove('dark-theme')
}

Toogle the sun and moon icons

And of course, the icons need to be switched from sun to moon and vice versa.

function changeIcons() {
 if (darkTheme) {
  ui.sun.classList.remove('hide')
  ui.moon.classList.add('hide')
 } else {
  ui.sun.classList.add('hide')
  ui.moon.classList.remove('hide')
 }
}

Finishing touches

All the interactivty has been added to make the light/dark mode work. But there is a problem. If a user revisits the website the previous light/dark preference will not be remembered. Therefore a check of the browser’s localStorage needs to made when the website loads.

web page with dark theme

Beneath the variable declarations at top of the script file, a check of the localStorage needs to be made, setting the darkTheme boolean accordingly. Then, of course, changing the colors and icons as described.

if (JSON.parse(localStorage.getItem('usersTheme'))) {
 darkTheme = true
} else {
 darkTheme = false
}
changeColors()
changeIcons()

That’s it.

Thank you for stumbling across this website and for reading my blog post entitled CSS and JavaScript for website dark mode