While doing some research for another article I decided to add a dark mode toggle to my website, but I don't want to add Javascript to my site at all. The question is, how do you add a dark mode toggle without using Javascript?
The Javascript way
Let's first explore the Javascript version to see how it might work.
This is our simple example HTML, nothing fancy here.
<div class="content">
Some content
</div>
<label for="dark-mode">Toggle Dark Mode
<input type="checkbox" id="dark-mode" /></label>
:root {
--lightBackground: white;
--lightColor: black;
--darkBackground: black;
--darkColor: white;
--background: var(--lightBackground);
--color: var(--lightColor);
}
.content {
background: var(--background);
color: var(--color);
height: 3rem;
}
We define our colors and we assign them to our container - which can be body
if you so desire.
const checkbox = document.querySelector('#dark-mode');
const content = document.querySelector('.content');
checkbox.addEventListener('change', (e) => {
const isDark = e.target.checked;
if (isDark) {
content.style.setProperty("--background", "var(--darkBackground)");
content.style.setProperty("--color", "var(--darkColor)");
} else {
content.style.setProperty("--background", "var(--lightBackground)");
content.style.setProperty("--color", "var(--lightColor)");
}
})
When the status of the checkbox changes, we change the CSS custom property value in kind. Simple, right? This comes with the added benefit that if we reference --background
or --color
anywhere else inside our element it will inherit these values!
The CSS Way
We can achieve the toggle part using the :checked
pseudo-class selector and by positioning the toggle before the content, we can then style our content using the general sibling combinator(~
) combinator. This is the reason why I haven't placed the input tag inside the label like in the first example.
<input type="checkbox" id="dark-mode" />
<label for="dark-mode">Toggle Dark Mode</label>
<div class="content">
Some content
</div>
:root {
--lightBackground: white;
--lightColor: black;
--darkBackground: black;
--darkColor: white;
--background: var(--lightBackground);
--color: var(--lightColor);
}
.content {
background: var(--background);
color: var(--color);
height: 3rem;
}
#dark-mode ~ .content {
--background: var(--lightBackground);
--color: var(--lightColor);
}
#dark-mode:checked ~ .content {
--background: var(--darkBackground);
--color: var(--darkColor);
}
We can also create a fancier version using CSS custom property fallback as a hacky if statement.