Easy CSS Theme Switching 🧚

I see many smart, but complex approaches to applying for dark and light mode, or user switchable color themes in web apps. In most cases, this doesn't need to be complicated. Here's a quick guide on how to do this with 2 lines of vanilla JS.

First we can assign a data attribute to our outermost tag (usually html, body or main), and then we can use CSS attribute selectors to target it. From in here, we can define our CSS variables, which can then be used throughout the application.

The only JavaScript required is a single function that just calls setAttribute('data-theme', 'theme-name') on our chosen root element, to change the value of the data-theme attribute. This can be triggered in the normal way (either with an onClick listener, or through a directive if you're using a frontend library like Vue).


Example

First, define some color schemes. Here I'm just using 2 variables as an example.

html[data-theme='light'] {
  --background: #fff;
  --primary: #000;
}

html[data-theme='dark'] {
  --background: #000;
  --primary: #fff;
}

html[data-theme='colorful'] {
  --background: #e896ff;
  --primary: #6e13f7;
}

And use the variables throughout you're app, in the same way you usually would

body {
    background: var(--background);
    color: car(--primary);
}

In JavaScript, write a quick function to change the current attribute:

function changeTheme(newTheme) {
    const htmlTag = document.getElementsByTagName('html')[0];
    if (htmlTag.hasAttribute('data-theme')) htmlTag.removeAttribute('data-theme');
    htmlTag.setAttribute('data-theme', newTheme);
}

Call the function that normal way you usually would, depending on which framework/ frontend library you're using. In this example, I'm just using some plain ol' HTML

<button onClick="toggleTheme('dark')">Dark Theme</button>
<button onClick="toggleTheme('light')">Light Theme</button>
<button onClick="toggleTheme('colorful')">Colorful Theme</button>

It's worth noting, that if you're using a CSS preprocessor (like SASS), then you will generally have more flexibility using CSS variables rather than SASS variables. Because SASS is compiled into color codes at build time, and so cannot be modified at runtime.


Detect if User Prefers Dark Mode

We can also check if the users device is set to dark mode, and default to that initially using the prefers-color-scheme media feature.

--background: #fff;
--primary: #000;

@media (prefers-color-scheme: dark) {
  --background: #000;
  --primary: #fff;
}

If the users device does not have a preference, then CSS will default to light mode. Some mobile devices by default will use light mode during the day, and dark mode at night.