Add Dark Mode to your Websites with CSS
Tags: css, webdev, ux, tutorial
Published: 2020-07-14 10:53:10

It's super easy to include a dark theme for your existing websites using CSS. In this tutorial, we're going to do this by taking advantage of [CSS Variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties).

We're going to have 3 different options for the theme - Auto, Light and Dark. The Light and Dark themes are pretty self explanatory, but the **Auto** theme is going to use the operating system theme setting to decide whether the site is going to be Light or Dark.

While I won't be showing you how to do this particular layout or include the content, here is an example of what we could create:

![Example of usage](https://dev-to-uploads.s3.amazonaws.com/i/rkdsn70hlxn1zaegd34i.jpg)

### Adding the HTML
Let's start with the HTML, you can think of the `value` attribute as being the identifier for each theme:
```html
<select id="theme">
    <option value="auto">Auto</option>
    <option value="light">Light</option>
    <option value="dark">Dark</option>
</select>
```
### Adding the CSS
Let's now add a bit of CSS to the `body` element, here is where you specify your colors for the Light Theme using CSS Variables:
```css
body {
    --background-color: #ffffff;
    --text-color: #000000;
}
```
Next, you'll want to make use of your CSS Variables throughout your style sheet - this is *key* to how our solution is going to work. For example, you might do:
```css
.main-content {
    background: var(--background-color);
    color: var(--text-color);
}

button {
    color: var(--text-color);
}
```
We're going to be implementing a dark theme by simply replacing the values of the above declared variables in instances where we're going to be using a dark theme. Let's add this CSS:
```css
:root {
    --dark-background-color: #111111;
    --dark-text-color: #eeeeee;
}

body.theme-dark {
    --background-color: var(--dark-background-color);
    --text-color: var(dark-text-color);
}
```
Now, if you add the `theme-dark` class to your `<body>` element, you should see the dark theme working. Shortly we'll be using JavaScript to toggle this value with the `<select>`, but let's implement our **Auto** option now:
```css
@media (prefers-color-scheme: dark) {
    body.theme-auto {
        --background-color: var(--dark-background-color);
        --text-color: var(--dark-text-color);
    }
}
```
The above CSS uses [Media Queries](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) which is checking if the operating system prefers a Dark Theme, and if so, we want to apply the nested ruleset for `body.theme-auto`.

We're basically saying "Does the operating system prefer dark mode, and does the `<body>` have a class of `theme-auto`? If so, let's use Dark Mode."

Try it out by changing your OS theme color, or even better, view the website on your phone with Dark Mode enabled.

### Adding the JavaScript
Now that our CSS is working, we can move onto getting our theme selector drop-down to work. Let's add the following JavaScript:
```js
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 waiting for the DOM to be ready for us to start using it, and once it's ready, we are listening for when the user chooses an option in the theme selector drop-down. Once they choose an option, we remove all existing theme classes from the `<body>` (if any) and then simply add the selected theme with `this.value`.

### A step further - remembering the theme
We could take this a step further and have the ability for the browser to remember the theme that was chosen upon a page refresh. To do this, we can use [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)

Let's add the following JavaScript, so we end up with this:
```js
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, upon choosing a theme, we save the theme to Local Storage by using `localStorage.setItem("theme", this.value)`. Following this up, on page load, we grab the previously saved theme into the `savedTheme` constant, with a default of `auto`. Once we have this, we simply apply the saved theme.

Adding to this, we are then looping through each one of our `<option>` elements and checking to see if the value is that of our saved theme, and if so, choose that option as "selected".

To test if it works, refresh the page, choose a theme, refresh again, and your theme should stick!

### Video Tutorial
If you instead prefer this in the form of a video tutorial, check it out here on my YouTube channel, dcode!
{% youtube 1KPd51v3Cok %}

Hope you guys enjoyed this one! This was my first DEV post so if you have any recommendations for improvement, please let me know. 

Cheers!😁