Using CSS to Implement a Dark Mode Theme for Your Websites

Lazy Developer's Blog
Bits and Pieces
Published in
4 min readFeb 9, 2023

--

Using CSS to add a dark theme to your current websites is really simple. We’ll do this in this article by utilizing CSS Variables.

The theme will be available in three different variations: Auto, Light, and Dark. However, the Auto theme will utilize the operating system’s theme option to determine whether the site will be Light or Dark. The Light and Dark themes are very clearly self-explanatory.

💡 Note: Using media queries and LocalStorage for theming is a great solution for smaller, weekend projects. However, if your projects are bigger, consider building a proper design system that is composable and scalable, using Bit’s open-sourced ThemeProvider that lets you quickly build a full theming solution with the Context API and design tokens.

To learn more about theming components with React:

Implementing the HTML

Starting with HTML, each theme’s identifier may be thought of as being included in the value attribute:

<select id="theme">
<option value="auto">Auto</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>

Implementing the CSS

Now that we’ve added some CSS to the body element, you may choose your Light Theme colors here by utilizing CSS variables:

body {
--background-color: #ffffff;
--text-color: #000000;
}

In order for our method to function, you’ll need to use your CSS Variables consistently across your style sheet. For instance, you could:

.main-content {
background: var(--background-color);
color: var(--text-color);
}

button {
color: var(--text-color);
}

In cases where we’re going to be employing a dark theme, we’re just going to replace the values of the aforementioned specified variables. Add this CSS now:

:root {
--dark-background-color: #111111;
--dark-text-color: #eeeeee;
}

body.theme-dark {
--background-color: var(--dark-background-color);
--text-color: var(dark-text-color);
}

The dark theme should now function if you apply the theme-dark class to your body> element. When the time comes, we’ll use JavaScript to change this value with the choose>, but for now, let’s put our Auto option in place:

@media (prefers-color-scheme: dark) {
body.theme-auto {
--background-color: var(--dark-background-color);
--text-color: var(--dark-text-color);
}
}

The aforementioned CSS makes advantage of Media Queries to determine whether the operating system likes a Dark Theme and, if it does, whether we should use the nested ruleset for the body. theme-auto.

Basically what we’re saying “Does the body have a class named theme-auto, and does the operating system favor dark mode? So, let’s go to Dark Mode.”

Change the OS theme color to test it out, or even better, browse the page on your phone while using Dark Mode.

Including JavaScript

We can now focus on getting our theme selection drop-down to function because our CSS is operational. Let’s include the next JavaScript:

function applyTheme(theme) {
document.body.classList.remove("theme-auto", "theme-light", "theme-dark");
document.body.classList.add(`theme-${theme}`);
}

document.addEventListener("DOMContentLoaded", () => {
document.querySelector("#theme").addEventListener("change", function() {
applyTheme(this.value);
});
});

Here, we are awaiting the DOM’s readiness so that we can begin utilizing it, and once it is, we are listening for when the user selects a choice from the theme selector drop-down menu. After they choose an option, we delete any previously installed theme classes from the <body> tag and then add the chosen theme by calling this.value.

Going a step further, keeping the subject in mind

We could go one step further and enable the browser to retain the theme selection made when refreshing the page. We can utilize LocalStorage to do this.

Let’s add the following JavaScript so that we have this:

document.addEventListener("DOMContentLoaded", () => {
const savedTheme = localStorage.getItem("theme") || "auto";

applyTheme(savedTheme);

for (const optionElement of document.querySelectorAll("#theme option")) {
optionElement.selected = savedTheme === optionElement.value;
}

document.querySelector("#theme").addEventListener("change", function () {
localStorage.setItem("theme", this.value);
applyTheme(this.value);
});
});

Now, after selecting a theme, we use localStorage.setItem(“theme”, this.value) to store the theme in local storage. Following this, we get the previously saved theme into the savedTheme constant, with a default value of auto, when the page loads. We just apply the stored theme once we have this.

In addition, we are cycling over all of our <option> components and selecting the option as “selected” if the value matches our stored theme.

Refresh the page, select a theme, and then refresh once again to see whether it works.

Please leave a comment if it functions for you.

Build Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--