DEV Community

Cover image for Simple JavaScript Theme Toggle
Ryan Furrer
Ryan Furrer

Posted on

Simple JavaScript Theme Toggle

Introducing ezToggle

This past weekend I created ezToggle - a simple way to add a theme toggle to your website using HTML, CSS, and basic JavaScript.

This is my first JavaScript success story but, for those of you that are looking for a simple way to add a light/dark theme toggle to your site this might be it!

Best of all, it includes minimal JavaScript so anyone should be able to use it.

var body = document.querySelector('body');
var bodyClass = body.classList;
var themeToggle = document.querySelector('#theme-toggle');
var footer = document.querySelector('.footer');
var light = document.querySelector('.light');
var dark = document.querySelector('.dark');

themeToggle.addEventListener('click', () => {
    body.classList.toggle("light");
    body.classList.toggle("dark");
    themeToggle.classList.toggle("btn-light");
    themeToggle.classList.toggle("btn-dark");
    footer.classList.toggle("footer-light");
    footer.classList.toggle("footer-dark");
});
Enter fullscreen mode Exit fullscreen mode

Now then, if your footer doesn't change colors that's 3 lines you could remove from this - the real secret is in using CSS Variables. Let's go over how you can implement this in your website!

Getting Started

To begin you'll need the CSS & JS files which you can find in the GitHub Repo.

I have recently discovered CSS Variables and absolutely love them and knew they'd be perfect for this project - and every project moving forward.

If you don't know, a CSS Variable is a CSS Property that you can define once and call throughout the document. This makes it great for things such as colors, transitions, margin/padding, and much more! Whatever you repeat throughout your CSS can be turned into a variable.

This is particularly great for themes because you can change the colors in the variable you set once and they will be changed throughout the entire document.

/*--------------------Reusable Variables--------------------*/
:root {
    /*--------------------Light Theme Variables (Default)--------------------*/
    --light-theme-background-color: #eee;
    --light-theme-darker-background-color: #ccc;
    --light-theme-text-color: #333;
    --light-theme-link-color: #ff6347;
    --light-theme-link-hover-color: #fa2600;
}
Enter fullscreen mode Exit fullscreen mode

More On CSS Variables

If you look at the code below you can see that I define the light theme in just 3 properties.

.light {
background: var(--light-theme-background-color);
color: var(--light-theme-text-color);
transition: var(--theme-change-timing);
}

Anywhere in the document I put var(--light-theme-text-color); it will take on the same color which we defined as #fff; in --light-theme-text-color: #333; Why did I define the themes in 2 classes .light and .dark? Because I can simply add said class to the body tag and BAM you've got your theme change.

Setup

HTML

First off, we need to apply a class of light to our body tag:

<body class="light">
Enter fullscreen mode Exit fullscreen mode

This sets the default theme to whatever is defined in our .light class. If you want the default theme to be dark, just change it to <body class="dark">.

CSS

There are a few steps involved in setting up the CSS. The first step is defining our CSS Variables in the :root psudo-class. The reason for this is so that you don't have to repeat the variable in different elements on the page. When you declare them in :root every element has access to them.

/*--------------------Reusable Variables--------------------*/
:root {
    /*--------------------Light Theme Variables (Default)--------------------*/
    --light-theme-background-color: #eee;
    --light-theme-darker-background-color: #ccc;
    --light-theme-text-color: #333;
    --light-theme-link-color: #ff6347;
    --light-theme-link-hover-color: #fa2600;

    /*--------------------Dark Theme Variables--------------------*/ 
    --dark-theme-background-color: #333;
    --dark-theme-darker-background-color: #111;
    --dark-theme-text-color: #eee;
    --dark-theme-link-color: #00fa9a;
    --dark-theme-link-hover-color: #00955b; 

    /*--------------------Other Variables--------------------*/ 
    --link-hover-timing: all 0.25s ease-in-out;
    --theme-change-timing: all 1s ease-in-out;
}
Enter fullscreen mode Exit fullscreen mode

Next I created some classes for each theme. This included a general .light and .dark theme for the body, as well as a btn-light and .btn-dark, and .footer-light and .footer-dark.

/*--------------------Light Theme Styles (Default)--------------------*/
.light {
    background: var(--light-theme-background-color);
    color: var(--light-theme-text-color);
    transition: var(--theme-change-timing);
}

.light a {
    color: var(--light-theme-link-color);
}

.light a:hover {
    color: var(--light-theme-link-hover-color);
}

.footer-light {
    background: var(--light-theme-darker-background-color);
}
Enter fullscreen mode Exit fullscreen mode

Just remember to apply any classes you create to the appropriate elements in your HTML file so they all get themed appropriately.

JavaScript

Firstly, we need to define our variables. You should do this at the top of the file so if you call these variables outside this theme toggle function they are available to them.

var body = document.querySelector('body');
var bodyClass = body.classList;
var themeToggle = document.querySelector('#theme-toggle');
var footer = document.querySelector('.footer');
var light = document.querySelector('.light');
var dark = document.querySelector('.dark');
Enter fullscreen mode Exit fullscreen mode

If you choose not to style the footer you can just remove it, however, for ezToggle I made the footer darker than the rest of the page so I had to define it here so it can be called upon in the following function:

themeToggle.addEventListener('click', () => {
    body.classList.toggle("light");
    body.classList.toggle("dark");
    themeToggle.classList.toggle("btn-light");
    themeToggle.classList.toggle("btn-dark");
    footer.classList.toggle("footer-light");
    footer.classList.toggle("footer-dark");
});
Enter fullscreen mode Exit fullscreen mode

The function listens for a click on the themeToggle button - the one that reads "Change Theme" on the website

Upon the button being clicked it first identifies the classes of the element it is attached to. Followed by .toggle it then toggles (surprise) the specified class onto said element. It toggles between the light and dark classes.

Wrapping Up

Here's a summary of the steps needed to apply ezToggle to your website:

  1. Apply light or dark class to `body` in your HTML
  2. Define your CSS variables in the :root pseudo-class. Make sure you change, add, or remove any colors you need for your theme.
  3. Create, add, or remove any necessary classes for your themes and any items getting themed.
  4. Be sure to add these classes to the appropriate elements in your HTML file
  5. Define JavaScript Variables
  6. Enjoy your theme toggle!

I hope you enjoyed and understood my first technical blog. I'm looking forward to doing more of these in the future.

If you have any questions or issues using ezToggle please don't hesitate to reach out to me here on DEV or on Twitter.

References

Top comments (10)

Collapse
 
link2twenty profile image
Andrew Bone • Edited

You could so something like

:root {
    /*--------------------Light Theme Variables (Default)--------------------*/
    --light-theme-background-color: #eee;
    --light-theme-darker-background-color: #ccc;
    --light-theme-text-color: #333;
    --light-theme-link-color: #ff6347;
    --light-theme-link-hover-color: #fa2600;

    /*--------------------Dark Theme Variables--------------------*/ 
    --dark-theme-background-color: #333;
    --dark-theme-darker-background-color: #111;
    --dark-theme-text-color: #eee;
    --dark-theme-link-color: #00fa9a;
    --dark-theme-link-hover-color: #00955b; 

    /*--------------------Other Variables--------------------*/ 
    --link-hover-timing: all 0.25s ease-in-out;
    --theme-change-timing: all 1s ease-in-out;
}

body[data-theme=light] {
  --theme-background-color: var(--theme-light-background-color);
  --theme-darker-background-color: var(--theme-light-darker-background-color);
  --theme-text-color: var(--theme-light-text-color);
  --theme-link-color: var(--theme-light-link-color);
  --theme-link-hover-color: var(--theme-light-ink-hover-color);
}

body[data-theme=dark] {
  --theme-background-color: var(--theme-dark-background-color);
  --theme-darker-background-color: var(--theme-dark-darker-background-color);
  --theme-text-color: var(--theme-dark-text-color);
  --theme-link-color: var(--theme-dark-link-color);
  --theme-link-hover-color: var(--theme-dark-ink-hover-color);
}

var body = document.querySelector('body');
var themeToggle = document.querySelector('#theme-toggle');

themeToggle.addEventListener('click', () => {
  var theme = body.dataset.theme;
  theme = theme == "dark" ? "light" : "dark"
});
Collapse
 
ryandotfurrer profile image
Ryan Furrer

What is the benefit of using dataset rather than a class?

Collapse
 
link2twenty profile image
Andrew Bone

The only benefit would be that you don't have to remove the old class simple override the dataset.

The main advantage of this method is that you don't need to change classes in several places. Simply change the dataset, or class if you prefer, on the body and everything else follows automatically.

Thread Thread
 
ryandotfurrer profile image
Ryan Furrer

I see! Interesting - I'm still (obviously) a novice in JS and definitely want to look more into this.

Thanks so much for reading and commenting, Andrew!

Collapse
 
tomayac profile image
Thomas Steiner

Along these lines, here's a custom element called <dark-mode-toggle> that initially respects the user's prefers-color-scheme user preference setting and also optionally allows for manually overriding it. Read more about it in this article (also mirrored here on DEV).

Collapse
 
ryandotfurrer profile image
Ryan Furrer

Ooh thanks for the link! I'll check it out today after work as that sounds like the best solution so far. Thanks, Thomas!

Collapse
 
torstendittmann profile image
Torsten Dittmann

You can also add "prefers-color-scheme" to identify if the user uses light or dark mode in his system.

developer.mozilla.org/en-US/docs/W...

Collapse
 
ryandotfurrer profile image
Ryan Furrer

Yes! This was on my list of things to add to it, actually. Thanks for the link - and reading!

Collapse
 
emma profile image
Emma Goto 🍙

Nice!

Collapse
 
ryandotfurrer profile image
Ryan Furrer

Thank you!