DEV Community

Cover image for Create A Dark/Light Mode Switch with CSS Variables
Ananya Neogi
Ananya Neogi

Posted on

Create A Dark/Light Mode Switch with CSS Variables

Giving your users a way to customise the interface to their preference is a huge win for user experience. Here we are going to provide the user with a simple switch to toggle between dark mode and light mode and we will also try to remember their preference for future visits.

Let's begin!

If you don't have a website of your own to which you wish to add this functionality, use this demo website to follow along.

Adding the CSS

We will be adding CSS custom properties also known as CSS variables, which we can reference and modify throughout the document. If you wish to read more about custom properties you can read on MDN.
Here's the tldr; version -

Custom properties (sometimes referred to as CSS variables or cascading variables) are entities defined by CSS authors that contain specific values to be reused throughout a document. They are set using custom property notation (e.g., --main-color: black;) and are accessed using the var() function (e.g., color: var(--main-color);)

First, we'll add our light or default mode css variables to the :root pseudo class. It matches with the root element in your document tree, generally the <html> tag. We will use :root because we want to avail the variables globally.

:root {
    --primary-color: #302AE6;
    --secondary-color: #536390;
    --font-color: #424242;
    --bg-color: #fff;
    --heading-color: #292922;
}
Enter fullscreen mode Exit fullscreen mode

Second, we'll add our dark mode css variables.

[data-theme="dark"] {
    --primary-color: #9A97F3;
    --secondary-color: #818cab;
    --font-color: #e1e1ff;
    --bg-color: #161625;
    --heading-color: #818cab;
}
Enter fullscreen mode Exit fullscreen mode

What is [data-theme="dark"]? This means we are referencing a data attribute called data-theme with a value "dark". We will find the use of it in a while.

Then, we can reference these variables in our stylesheets like so-

body {
    background-color: var(--bg-color);
    color: var(--font-color);

    /*other styles*/
    .....
}

h1 {
    color: var(--secondary-color);

    /*other styles*/
    .....
}

a {
    color: var(--primary-color);

    /*other styles*/
    .....
}
Enter fullscreen mode Exit fullscreen mode


Adding the HTML "toggle switch markup"

This is essentially just a checkbox, however we will add some additional markup to style like a toggle switch. I referenced the styles from this codepen.

<div class="theme-switch-wrapper">
    <label class="theme-switch" for="checkbox">
        <input type="checkbox" id="checkbox" />
        <div class="slider round"></div>
  </label>
  <em>Enable Dark Mode!</em>
</div>
Enter fullscreen mode Exit fullscreen mode
/*Simple css to style it like a toggle switch*/
.theme-switch-wrapper {
  display: flex;
  align-items: center;

  em {
    margin-left: 10px;
    font-size: 1rem;
  }
}
.theme-switch {
  display: inline-block;
  height: 34px;
  position: relative;
  width: 60px;
}

.theme-switch input {
  display:none;
}

.slider {
  background-color: #ccc;
  bottom: 0;
  cursor: pointer;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
  transition: .4s;
}

.slider:before {
  background-color: #fff;
  bottom: 4px;
  content: "";
  height: 26px;
  left: 4px;
  position: absolute;
  transition: .4s;
  width: 26px;
}

input:checked + .slider {
  background-color: #66bb6a;
}

input:checked + .slider:before {
  transform: translateX(26px);
}

.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}

Enter fullscreen mode Exit fullscreen mode


Adding the JavaScript

The final part is to add the bit of JavaScript to tie it all together.
We have 3 tasks in hand-

  • Add event handlers to handle accordingly the check/uncheck event of toggle-switch
  • Store the user preference for future visits
  • Check for saved user preference, if any, on load of the website

Adding the event handlers


const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');

function switchTheme(e) {
    if (e.target.checked) {
        document.documentElement.setAttribute('data-theme', 'dark');
    }
    else {
        document.documentElement.setAttribute('data-theme', 'light');
    }    
}

toggleSwitch.addEventListener('change', switchTheme, false);

Enter fullscreen mode Exit fullscreen mode

Remember, the data-theme attribute we referenced in CSS above, this is where it's getting added to our root element.


Store the user preference for future visits

We will use browser's localStorage to store the user preference.
Let's modify our switchTheme function -

function switchTheme(e) {
    if (e.target.checked) {
        document.documentElement.setAttribute('data-theme', 'dark');
        localStorage.setItem('theme', 'dark'); //add this
    }
    else {
        document.documentElement.setAttribute('data-theme', 'light');
        localStorage.setItem('theme', 'light'); //add this
    }    
}

Enter fullscreen mode Exit fullscreen mode

Check for saved user preference, if any, on load of the website

We will check if the theme preference is saved, if yes then we will, accordingly-
- set our data-theme attribute
- check/uncheck our toggle-switch checkbox


const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;

if (currentTheme) {
    document.documentElement.setAttribute('data-theme', currentTheme);

    if (currentTheme === 'dark') {
        toggleSwitch.checked = true;
    }
}

Enter fullscreen mode Exit fullscreen mode

That's it! Check out the full demo below.

I recently added this to my website, so check that out as well, maybe!



Pro-Tip: How to decide on the color scheme?
My suggestion is to stay in the same spectrum of your primary or brand color and generate a palette out of it. Use the darkest shade from the palette as the background color and the lighter shades as font colors when in dark mode. I used this color shades generator for generating my color palette.

Even if you don't end up using the exact colors generated, it is still a good place to start. Even I ended up fine tuning the colors I ultimately used.


Resources

  1. Learn CSS Variables in 5 minutes

Oldest comments (61)

Collapse
 
lucasgdb profile image
Lucas Bittencourt

Thanks! It will help me a lot. I've been using it wrong (but working), now you've cleared my mind. :)

Collapse
 
ben profile image
Ben Halpern

Just how we do it with dev.to!

CSS variables are awesome.

Collapse
 
ananyaneogi profile image
Ananya Neogi

Love the dark mode on dev.to! 🙂

Collapse
 
gevv profile image
gevv

@Ananya Neogi

Hi,

Dark mode does not not work link open new window (target="_blank" links)

is there a solution?

Thanks
Best regards

Collapse
 
mittalyashu profile image
Yashu Mittal

Wait, what! There is dark theme for dev.to, nobody told me about that. 😂

Collapse
 
ben profile image
Ben Halpern

Dark mode is new, and it's fabulous (with a few kinks that still need to be worked out).

Thread Thread
 
mittalyashu profile image
Yashu Mittal

Oh! I see. How can I enable dark mode?

Thread Thread
 
ananyaneogi profile image
Ananya Neogi

Settings ➡ Misc. On that page you'll find it under "Style Customization"

Thread Thread
 
mittalyashu profile image
Yashu Mittal

Awesome, thanks. Looks cool.

Dark mode for dev.to

Collapse
 
zonayedpca profile image
Zonayed Ahmed

Where is bro? Just tell me where is it? I didn't know about it...

Collapse
 
bhupesh profile image
Bhupesh Varshney 👾

Nice post 👌👌 🤩
Gonna embed into my portfolio

Collapse
 
ananyaneogi profile image
Ananya Neogi

Yes, this makes more sense. Thanks! 🙂
I'll update the demo.

Collapse
 
rhymes profile image
rhymes

Thank you Ananya! Great article, loved the tip about how to come up with a night theme :)

Collapse
 
stealthmusic profile image
Jan Wedel

Great post. I would love to add a Dark theme to my website, but probably won’t have the time 😭. Bookmarked your article anyways 🤓

Collapse
 
sagar profile image
Sagar

Super duper thanks for article.

Collapse
 
lizardbird profile image
Liz Jewell

Thanks for this! I haven't tried my own light/dark mode since I tried implementing it on my first bootcamp project a couple years ago. I technically got it to work, but the code was not this DRY as I made two individual buttons that would add/remove a "dark" or "light" class on the entire body element. 😂 Your solution is much better!

Collapse
 
desi profile image
Desi

this is great and so helpful - thanks so much! I do have one question - in the js, where does "light" come from? unless I'm missing it, that's not defined in the CSS, is it?

Collapse
 
ananyaneogi profile image
Ananya Neogi

Hi Desi!
You're right, it's not defined anywhere.
If CSS doesn't find any specific styles related to light it will default back to the normal variables defined in :root.

Why I added it?
I added it so that we can use it while checking for the saved theme in localStorage further and add it to the root element. It will also be useful in cases where you might want to add some specific styles for light apart from the default styles.

I hope this helps 🙂

Collapse
 
desi profile image
Desi

Awesome, thanks so much! Explanation makes perfect sense.

Thread Thread
 
ananyaneogi profile image
Ananya Neogi

You're welcome 🙂

Collapse
 
singhofen profile image
Chase S.

Very Cool! Trying to figure out how to toggle between bg color & bg picture.

Collapse
 
simoncoudeville profile image
Simon Coudeville

Very cool.

Have you thought about the prefers-color-scheme media feature? How could this be implemented in this script? You should check that too In my opinion. The toggle would have to automatically switch to the preferred color scheme.

Collapse
 
chicuong95 profile image
Cuong

Thanks Ananya, it's helpful for me

Collapse
 
rugk profile image
rugk

You won't believe it, but actually you can nowadays even take the operation system setting for the dark mode and apply/get that, so your users don't even need that toggle, or at least use the version they prefer, by default.
With CSS and JS…

Collapse
 
deschainxu profile image
DeschainX 𓅓

In my case, I would offer two toggle for users which are auto mode (system dark mode) and manual Light/Dark toggle, so users can choose whatever they prefer.

Collapse
 
rolandixor profile image
Roland Taylor • Edited

I'm planning to experiment with something like this, but using CSS only (no javascript).

Collapse
 
highcenburg profile image
Vicente G. Reyes

This isn't not working anymore?