Create a darkmode using minimal JavaScript

- 7 min read

Introduction

In this step-by-step tutorial, I’ll show you how to create a dark mode for your website using minimal JavaScript. You can follow along and see the results in real time with the interactive elements included.

There are various ways to implement dark mode, ranging from simple to complex. Here, I’ll walk you through a straightforward method that relies on three key principles:

  • CSS variables to easily switch color values between modes
  • A checkbox (or other input) to capture the user’s preference
  • localStorage to make the selected mode persist across pages

This is the same approach I’ve used on this site, so feel free to check it out!

Setting up the HTML

First things first, let’s create a basic html template.
We’ll need a checkbox and some content.

<main class="demo">
	<input id="demo-darkmode" type="checkbox" />
	<label for="demo-darkmode">
		<!-- Checkbox's label -->
	</label>

	<div class="demo-content">
		<!-- Your website's content -->
	</div>
</main>
Result

CSS-only dark mode

Lorem ipsum dolor sit amet, a link consectetur adipiscing elit . Quisque maximus justo quis sapien ornare vehicula vitae at est another link.

We have our HTML structure, now let’s set the colors.

Add some CSS variables

Let’s declare 3 CSS variable for now.
Put them in the :root selector so you are sure they are accessible everywhere.
We declare 1 for the text, 1 for the background and one for the links.

:root {
	--c-text: #493c37;
	--c-background: #eddfe0;
	--c-primary: #b392f0;
}

Now let’s link these variables to their elements.

h1,
p {
	color: var(--c-text);
}

main {
	background-color: var(--c-background);
}

a {
	color: var(--c-primary);
}

From now on, when you change the value of the CSS variables, it will impact all the elements linked to it.

You can try and change the color values in the interactive example below.

Result

CSS-only dark mode

Lorem ipsum dolor sit amet, a link consectetur adipiscing elit . Quisque maximus justo quis sapien ornare vehicula vitae at est another link.

Now we have our HTML and CSS variables set up, but we still miss the main part: the darkmode.
It’s pretty simple from here. We have to define the colors we want when we enter the darkmode. We also have to define when we are in a darkmode.

To know when we are in darkmode, we just have to see if the input is checked.
We can do that easily in CSS using the relatively new selector :has().
Here we watch if the :root element has the input (#demo-darkmode) in a checked state. If it’s the case, we reassign the CSS variable with new values.

/* Default variables values */
:root {
	--c-text: #493c37;
	--c-background: #eddfe0;
	--c-primary: #b392f0;
}

/* Variables values when the input is checked */
:root:has(#demo-darkmode:checked) {
	--c-text: #fff;
	--c-background: #333;
	--c-primary: #98fb98;
}

With just that addition, clicking the darkmode checkbox will switch the declared colors.
You can try it out in the interactive demo below.

Result

CSS-only dark mode

Lorem ipsum dolor sit amet, a link consectetur adipiscing elit . Quisque maximus justo quis sapien ornare vehicula vitae at est another link.

Our darkmode is working 🎉
Currently, if we check the darkmode checkbox and reload the page, it will reset to its original state. To fix this, we can make the darkmode persistant

Add a localStorage

Adding localStorage to maintain darkmode is pretty straightforward.

We watch the checkbox, and when it changes state, we save it in a localStorage item. We give this item a name (here “demo-darkmode”), and the state of the checkbox (if it’s checked or not).

On the page load, we also modify the checkbox state by applying the localStorage item value.

const checkbox = document.querySelector('#demo-darkmode');

// When the checkbox state change, we store its state in the localStorage
checkbox.addEventListener('change', function (event) {
	localStorage.setItem('demo-darkmode', event.currentTarget.checked);
});

// Change the checkbox state depending of the value stored in the localStorage
checkbox.checked = localStorage.getItem('demo-darkmode') === 'true';

If you check the checkbox below and reload the page, the interactive demo should stay in darkmode.

Result

CSS-only dark mode

Lorem ipsum dolor sit amet, a link consectetur adipiscing elit . Quisque maximus justo quis sapien ornare vehicula vitae at est another link.

In less than 5 lines of JavaScript and 20 lines of CSS, we managed to create a darkmode.
It’s functional, easy to implement, easy to maintain, and supported by over 88% of browsers.

Want to see all the code in one place ? Check out the CodePen I created.

What’s next?

There are still a lot of ways to improve the darkmode from here:

  • Implement prefers-color-scheme, which will automatically apply the user’s preferred mode based on their system settings.
  • Add animations to make the transition smoother
  • Add more than just a light and dark mode
  • Change other values than just colors

It’s up to you to explore and decide how you want to enhance your dark mode!

Support My Work

Feel free to leave your comments or questions by email at hey@theosoti.com.
If you found this article helpful, please share it with your peers and join my newsletter below for more web development tutorials.

Happy coding!

    No spam. Unsubscribe at anytime.