How to Code a Simple Dark Mode Toggle
August 4, 2019

This is a step by step guide that will show you how to code a basic website dark mode toggle button using simple HTML, CSS, and Javascript.
Here is a working demo of what we will be creating.
Try clicking the toggle button and reloading the page. You will see that your selection is stored and applied when the page loads.
Here is the direct link to this demo. If you simply want to download the code you could right click on the link and select to save the source code to your computer. I’ve also included another basic version that has a really small toggle button only in the top right of the window.
In this example the data is stored locally in the browser using localStorage. The variable is checked the next time the page loads (or another page in the site) and the CSS styling is applied accordingly.
First will create a basic webpage with the core html elements:
<!DOCTYPE html>
<html>
<head>
<title>Dark Mode Toggle</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div class="container">
<h1>Dark Mode Toggle</h1>
<button
class="light-mode-button"
aria-label="Toggle Light Mode"
onclick="toggle_light_mode()">
<span></span>
<span></span>
</button>
</div>
</body>
</html>
Note, I have included the content in a ‘container’ div which is only used to center the content on the page. I’ve also included the meta viewport tag because this is generally a must have for any webpage to scale appropriately on mobile devices. You will also notice that my button includes only two span elements which will be used to create the two button components, the toggle button background and the toggle button circular switch.
Next add the Javascript that will handle the toggling function immediately before the closing body tag. Basically this code:
- Gets the body element
- Checks the lightMode variable value
- If the lightMode variable = ‘dark’ it sets it to ‘light’ and sets the custom light-mode attribute of the body to light. Or vice versa.
Please note: In this example I decided to use a custom data attribute that I named ‘light-mode’ however you could simply toggle css classes if you prefer. For more information on data attributes checkout this link. I also use a particular method where I create a variable for the body tag which I call ‘app’. You could just refer to the body tag directly. I find this method offers a bit more flexibility, particularly when using tools such Codepen where it is not straightforward to include an id or class on the body element.
Place this code immediately before the closing body tag:
<script>
function toggle_light_mode() {
var app = document.getElementsByTagName("BODY")[0];
if (localStorage.lightMode == "dark") {
localStorage.lightMode = "light";
app.setAttribute("light-mode", "light");
} else {
localStorage.lightMode = "dark";
app.setAttribute("light-mode", "dark");
}
}
</script>
Next we will add some CSS styles for the button element. You can include the CSS as an external css document (and link to it in the head), or simple place it inline in the head immediately before the closing head tag between like so:
<!DOCTYPE html>
<html>
<head>
<title>Dark Mode Toggle</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
/* Light Mode Button Styles
--------------------------- */
.light-mode-button {
background:0;
border: 0;
box-sizing: border-box;
cursor: pointer;
height: 40px;
width: 100px;
position: relative;
border: 1px solid rgba(255,255,255,0);
}
.light-mode-button:focus {
outline:none; /* Not ideal for accessibility */
}
.light-mode-button span:nth-child(1) {
position: absolute;
top:0;
left:0;
width: 100px;
height:40px;
border-radius: 20px;
background-color: #d6d7db;
box-shadow: inset 1px 1px 3px 0 rgb(0 0 0 / 40%);
transition: .3s;
}
.light-mode-button span:nth-child(2) {
position: absolute;
top:5px;
left:5px;
width: 30px;
height: 30px;
background-color: #fff;
border-radius: 50%;
box-shadow: 1px 1px 2px 0 rgb(0 0 0 / 40%);
transition: .3s;
}
</style>
</head>
<body>
<!-- ... -->
Next we will add some CSS styling for the dark mode. Add this after the previous CSS before the closing style tag.
/* Light & Dark Mode Styles
--------------------------- */
body {
background-color: #f6f6f6;
transition: background-color .3s;
}
body[light-mode=dark] {
background-color: #141516;
color: #ced4e2;
}
body[light-mode="dark"] .light-mode-button span:nth-child(1){
background-color: #ced4e2;
color: #141516;
}
body[light-mode=dark] .light-mode-button span:nth-child(2) {
left: 65px;
background-color: #141516;
}
Now check your document in the browser and the toggle function should work, at least basically. At this point it is good to view the code in the inspector and notice how the Javascript adds the attribute to the body tag and updates it accordingly.
Note, I used slightly off shades of black and white but you can use whatever specific style values you want. I used #141516 for the dark grey and #ced4e2 for the light grey. You can see that the main styles are either a dark background with light elements or vice versa.
This is all fine for the basic toggling mechanism however we also want the page to apply the most recently set state when the page is completely closed and re-opened.
Add the following code in the html immediately below the opening body tag. I found that it was important to include this code near the top of the page so it is run as soon as possible.
This code simply checks if the lightMode variable = dark and if so sets the attribute value accordingly for the css to apply to. Otherwise the page loads in the normal default ‘light’ mode.
<script>
var app = document.getElementsByTagName("BODY")[0];
if (localStorage.lightMode == "dark") {
app.setAttribute("light-mode", "dark");
}
</script>
Now try switching to the dark mode and then closing and reopening the page. Hopefully it is all working OK.
In the demo above I also added some basic styles for the font and to position the elements in the center of the browser window:
/* Some Custom Styles
--------------------------- */
body {
font-family: 'Inter', sans-serif;
text-align: center;
}
h1 {
font-weight: 600;
margin-top: 0;
}
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
min-height: 100vh;
position: absolute;
top: 0;
}
If by chance you want to use exactly the same font (‘Inter semi-bold’), add this code between the head tags:
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@600&display=swap" rel="stylesheet">
Taking it Further
One thing that you can also do, which I think is pretty cool anyway, is to include a script that will listen to changes in localStorage data and then do something if a change is detected. For example if you include the following code in your Javascript and you have the webpage (or website) open in two different browser windows (using the same browser), when you update the light mode on one of the pages any other pages that are open will synchronise with the same value.
window.addEventListener("storage", function () {
if (localStorage.lightMode == "dark") {
app.setAttribute("light-mode", "dark");
} else {
app.setAttribute("light-mode", "light");
}
}, false);
Otherwise this is the just the first time I have attempted to code a simple dark mode toggle and I’m sure there are plenty of ways to achieve this. For further reading you might want to checkout this guide to working with dark modes on CSS tricks.
If you read this article you will find that there is also a method to apply a dark mode to a website based on the users computer system settings, however personally I have found this method to be a bit awkward so for now I am sticking to this more manual approach in my websites and apps. If you checkout some the apps I have developed such as Simple Counter or Words of Wisdom you will see that I have extended this method to create a simple theme switching mechanism, so the user can select from different colour schemes which will be automatically applied the next time the app is loaded. I have a plan to write a theme switching tutorial at some point, hopefully soon.
Don’t forget if you have any problems with your code here are links to the working demo and the streamlined version (with a small button in the top right).
Otherwise please don’t hesitate to get in touch with any feedback via email at contact@henryegloff.com.
I would love to make it my thing to create tutorials and learning resources that are 100% free with no strings attached.
If this tutorial was useful for you please consider showing your appreciation and offering your support. It will make my day!
Buy me a coffee