Signup/Sign In
LAST UPDATED: JUNE 23, 2023

Build a Theme Switcher for Your Website with JavaScript

Technology #javascript

    You might have noticed that nowadays many websites have a theme switcher on top of their website. The theme switcher can also be used as a dark mode switcher. In this article, we’ll be building a theme switcher like that.

    I am not going to focus a lot on the styles; instead, we’ll try to understand the logic about creating it. Also, the theme switcher will be persistent. The selected theme will be stored in the browser and will apply the same theme even after reloading. We’ll implement this using the browser’s local storage. So, let’s start building.

    Things you need to know

    and you are good to go.

    Here's our Complete App

    Theme Switcher with Javascript

    One thing I must explain before we start building the Markup is custom data attributes in HTML.

    Build a Theme Switcher for Your Website with JavaScript

    What are HTML Data Attributes?

    There may be situations when we have to store some information associated with DOM elements. Let's take an example, suppose we have a list of employees and we want to save their IDs, which we can use to manipulate them using the DOM. Before HTML5, we could have used classes or IDs, but this is not an impressive solution. HTML5 introduced us to the concept of Custom Data Attributes. Any attribute that starts with data- is a custom data attribute. We also have special HTML data tags in HTML 5.

    For example, we can name data-identity to create a custom data attribute for employee ID. Two things to keep in mind while creating a data attribute is that the value that is stored inside data attributes can only be of string type. And the second point is that we cannot use any valid HTML attribute as a name for data attributes. Like, data-id is not appropriate.

    We can access these attributes in JavaScript with dataset property.

    Suppose we want to access the identity attribute from before. We can access this using the below codes,

    let employee = document.getElementByClassName("employee-table");
    let empID = employee.dataset.identity;
    // Or
    let empID = employee.dataset['identity']

    Now that you have a basic understanding of the data attributes, let's start building our Theme Switcher.

    File Structure:

    |--themes
    
    |------dark.css
    
    |------light.css
    
    |------purple.css
    
    |------sky.css
    
    |--index.html
    
    |--script.js
    
    |--style.css

    Now that we know the file structure, let's begin the coding.

    Building the Markup

    As you can understand from the gif above, we are not using any high-level design. We have a simple header section with the name of our app and the buttons to change the themes. Our body contains an image and some random texts. We are also using the Roboto font to style the document.

    <!DOCTYPE html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Theme Switcher</title>
        <link rel="stylesheet" href="./style.css">
        <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700;900&display=swap" rel="stylesheet">
        <link rel="stylesheet" id="switcher-id" href="">
    </head>
    <body>
        <header>
            <h1>???? THEME SWITCHER</h1>
            <div class="theme-switches">
    
                <div data-theme="light" class="switch" id="switch-1"></div>
    
                <div data-theme="sky" class="switch" id="switch-2"></div>
    
                <div data-theme="purple" class="switch" id="switch-3"></div>
    
                <div data-theme="dark" class="switch" id="switch-4"></div>
    
            </div>
        </header>
    
        <div class="container">
            <div class="box">
                <img src="https://images.unsplash.com/photo-1597926588114-2d9c1190b5c7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=923&q=80"
                    alt="Placeholder" class="image">
                <div class="text">
                    <h3>A Sweet Heading</h3>
                    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod 
                    tempor incididunt ut labore et dolore magna aliqua. Ut enim 
                    ad minim veniam, quis nostrud exercitation ullamco laboris 
                    nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor 
                    in reprehenderit in voluptate velit esse cillum dolore eu fugiat 
                    nulla pariatur. Excepteur sint occaecat cupidatat non proident, 
                    sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                </div>
            </div>
        </div>
        <script src="./script.js"></script>
    
    </body>
    
    </html>

    That is just a few lines of Markup. We have added the fonts in the header, default styles stylesheets, and a stylesheet link with a blank href. This blank href will be used to attach our theme designs. You can also see we are using a data-theme custom data attribute to keep track of the theme selected. We will use the IDs of theme switches to design the switches. In our main body, we are using an image from Unsplash. And some random text. And finally, in the end, we are linking our script file.

    Also Read: JavaScript Browser Object Model

    Styling Our Default CSS

    As you might have observed, we have two stylesheets tagged in our HTML document. The first stylesheet is responsible for all the default styles our website will have, like font sizes, viewport height-width, and image sizes. And the second one will be responsible for the specific theme designs.

    We’ll also use CSS variables in this example. The benefits of using variables are that we can declare a variable once and use it multiple times in a document. Declaring variables in CSS are pretty easy. We usually define them in the :root selector. Any name that starts with -- is a CSS variable. Example,

    root {
        --text-color: #000;
        --back-color: #eee;
    }

    In our default stylesheet, we will be declaring four variables that will be used for the theme switches. Then we'll reset our document.

    We'll use flex-box to design the theme switches. If you are not familiar with Flexboxes. The display:flex property set on the parent element will make the child elements horizontal. The justify-content:center will center the elements.

    For the growing effect on the switches, we are using the CSS scale transform property. We are scaling the element 1.2 times of the original. And for the smooth effect, we are using transition: 0.3s all;. Then, we are using our variables to design the switches. We are adding the variables as background-color on the switches to design them.

    You can check the code, and you'll get a clear idea. We are also using some basic media queries for responsiveness. I think I don't have to explain the whole code because it is pretty basic. And I've discussed the portions I thought needed some explanation. Here's the full CSS code.

    :root {
      --light: #ffffff;
      --sky: #7f9cf5;
      --purple: #97266d;
      --dark: #81899b;
    }
    
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    body {
      font-family: 'Roboto', sans-serif;
      height: 100vh;
      overflow-x: hidden;
    }
    
    header {
      text-align: center;
      font-size: 30px;
      padding: 50px 0;
    }
    
    .theme-switches {
      display: flex;
      justify-content: center;
    }
    
    .switch {
      border: 2px solid black;
      border-radius: 50px;
      height: 30px;
      width: 30px;
      margin: 10px;
      cursor: pointer;
    }
    
    .switch:hover {
      transform: scale(1.2);
      transition: 0.3s ease-in-out;
    }
    
    #switch-1 {
      background-color: var(--light);
    }
    
    #switch-2 {
      background-color: var(--sky);
    }
    
    #switch-3 {
      background-color: var(--purple);
    }
    
    #switch-4 {
      background-color: var(--dark);
    }
    
    .container {
      max-width: 80%;
      margin: 0 auto;
    }
    
    .box {
      display: flex;
      justify-content: space-around;
      margin-top: 100px;
    }
    
    .box img {
      max-height: 300px;
      width: auto;
      border-radius: 20px;
      margin: 20px;
    }
    
    .text {
      width: 50%;
    }
    
    .text h3 {
      font-size: 35px;
      padding: 30px 0;
      font-weight: 600;
    }
    
    .text p {
      font-size: 20px;
      font-weight: 400;
    }
    
    /* Media Query */
    @media (max-width: 768px) {
      header h1 {
        font-size: 25px;
      }
    
      .box {
        display: flex;
        flex-wrap: wrap;
      }
    
      .box img {
        max-width: 80vw;
      }
    
      .text {
        width: 80%;
      }
    }

    Styling Our Themes

    Now, let's set up our theme files.

    First, let’s understand the properties that change when we change a theme. Let's make a list of them.

    1. Heading Background

    2. Text Colors

    3. Image Border

    4. Body Background Color

    Now that we've outlined the colors we’ll be changing, most of our work is done. First, create a file called light.css for the light styles.

    light.css

    :root {
      --back-color: #eee;
      --primary-color: #000000;
      --header-back: #5d5d5d;
      --header-text: #eee;
    }
    
    body {
      background-color: var(--back-color);
      color: var(--primary-color);
    }
    
    header {
      background-color: var(--header-back);
      color: var(--header-text);
    }
    
    .box img {
      border: 2px solid var(--primary-color);
    }

    As you can see, we've defined the colors we'll be using in the light theme as variables. Then we are just adding the colors to the properties we want to change. Pretty simple, right? I am attaching the other theme files below,

    sky.css

    :root {
      --back-color: #c3dafe;
      --primary-color: #3c366b;
      --header-back: #5f718d;
      --header-text: #eee;
    }
    
    body {
      background-color: var(--back-color);
      color: var(--primary-color);
    }
    
    header {
      background-color: var(--header-back);
      color: var(--header-text);
    }
    
    .box img {
      border: 2px solid var(--primary-color);
    }

    purple.css

    :root {
      --back-color: #fed7e2;
      --primary-color: #702459;
      --header-back: #874f5e;
      --header-text: #eee;
    }
    
    body {
      background-color: var(--back-color);
      color: var(--primary-color);
    }
    
    header {
      background-color: var(--header-back);
      color: var(--header-text);
    }
    
    .box img {
      border: 2px solid var(--primary-color);
    }

    dark.css

    :root {
      --back-color: #81899b;
      --primary-color: #f9ffee;
      --header-back: #1a1d24;
      --header-text: #eee;
    }
    
    body {
      background-color: var(--back-color);
      color: var(--primary-color);
    }
    
    header {
      background-color: var(--header-back);
      color: var(--header-text);
    }
    
    .box img {
      border: 2px solid var(--primary-color);
    }

    As you can see, all our themes have the same styles, we’re just changing the color variables, and everything is ready.

    The JavaScript Part

    Here comes the most crucial part. Our JavaScript code is responsible for all the theme-changing things. Let’s first understand the logic behind our script file.

    First, we’ll loop through all the switches and store the dataset value into a variable. Then, we’ll pass the value into a function that will set the theme accordingly.

    We’ll get all the switches used in HTML using their class name and store those in a variable called switches.

    let switches = document.getElementsByClassName('switch');

    Then we’ll loop over the switches and will listen for the click event on the switches. In our case, we’ll store the

    value clicked inside a variable called theme. I’ll be using a for...in loop here. If you are not familiar with for...in Loop, check this article on our site.

    for (let i of switches) {
      i.addEventListener('click', function () {
        let theme = this.dataset.theme;
        console.log(theme);
      });
    }

    For your understanding, I’m the first console to log the value that is clicked. Every time we click on a switch, it’ll console.log its custom data attribute value. You can see the gif to get an idea.

    Theme Switcher Console.log

    Now we have to create a function called setTheme, which will set our theme. Let's see how it looks,

    function setTheme(theme) {
      if (theme == 'light') {
        document.getElementById('switcher-id').href = './themes/light.css';
      } else if (theme == 'sky') {
        document.getElementById('switcher-id').href = './themes/sky.css';
      } else if (theme == 'purple') {
        document.getElementById('switcher-id').href = './themes/purple.css';
      } else if (theme == 'dark') {
        document.getElementById('switcher-id').href = './themes/dark.css';
      }
    }

    We are passing the parameter which we got from the dataset into this function. We can also achieve the same with a switch case statement. Our blank stylesheet in the HTML has the switcher-id id in it. We are targeting that element and adding an href to it. We are keeping all our theme styles in a separate folder called themes. And we have to call this function from the loop. So, our final code for the loops will be,

    for (let i of switches) {
    
      i.addEventListener('click', function () {
    
        let theme = this.dataset.theme;
    
        console.log(theme);
    
        setTheme(theme);
    
      });
    
    }

    I think it's making sense now. We are almost done. The final thing is to implement the local storage here. The stored data in local storage is saved across browser sessions, and it is pretty similar to session storage. Though, the significant difference between these is, local storage does not have any expiry. Local storage creates a key-value pair to store data.

    The localStorage.getItem, with a name parameter, will create a key to save our values. In our example, we’ll be using a key called theme. So, our first step is to initiate it.

    let style = localStorage.getItem('style');

    The default property of a local storage element is null. So, our next step is to check if it’s null and if it is, we will set a theme value for it.

    if (style == null) {
        setTheme('light');
    } else {
        setTheme(style);
    }

    Here, if the value is null, we are setting the light theme as default. Otherwise, it'll set the value that is stored in the local storage.

    And finally, We have to set the value as per the clicked switch. We’ll achieve this using the setItem property of local storage.

    localStorage.setItem('style', theme);

    We’ll add this code before the end of the setTheme function. So, our complete script.js file will look like this,

    let switches = document.getElementsByClassName('switch');
    
    let style = localStorage.getItem('style');
    
    if (style == null) {
      setTheme('light');
    } else {
      setTheme(style);
    }
    
    for (let i of switches) {
      i.addEventListener('click', function () {
        let theme = this.dataset.theme;
        setTheme(theme);
      });
    }
    
    function setTheme(theme) {
      if (theme == 'light') {
        document.getElementById('switcher-id').href = './themes/light.css';
      } else if (theme == 'sky') {
        document.getElementById('switcher-id').href = './themes/sky.css';
      } else if (theme == 'purple') {
        document.getElementById('switcher-id').href = './themes/purple.css';
      } else if (theme == 'dark') {
        document.getElementById('switcher-id').href = './themes/dark.css';
      }
      localStorage.setItem('style', theme);
    }

    To learn more about the local storage web API, check this MDN article. You can see the value of local storage from the Inspect-->Application-->Local Storage. We can check the gif below to see how it changes.

    Theme Switcher 3 using Javascript

    Conclusion

    This simple yet impactful feature allows users to tailor the visual aesthetics to their liking, enhancing their engagement and satisfaction. From a coding perspective, building a theme switcher in JavaScript demonstrates your ability to create interactive and dynamic web experiences.

    As you explore the possibilities, remember that JavaScript is your key to unlocking a new level of user engagement and customization on your website.

    I hope you learned something new in this article. Feel free to comment on your thoughts. And you can find the complete source code here.

    Frequently Asked Questions(FAQs)

    1. What is a theme switcher?

    A theme switcher is a feature that allows users to change the visual appearance of a website by toggling between different themes or styles. It enables users to personalize their browsing experience and adapt the website's aesthetics to their preferences.

    2. Why should I build a theme switcher for my website?

    Building a theme switcher for your website enhances user experience by allowing visitors to personalize the visual aesthetics. It demonstrates your commitment to user satisfaction and provides a sense of customization, making your website more engaging and appealing.

    3. How can JavaScript be used to build a theme switcher?

    JavaScript can be used to build a theme switcher by manipulating the CSS styles of your website dynamically. By leveraging JavaScript's ability to access and modify HTML elements, you can update the stylesheets and apply different themes based on user interactions or preferences.

    4. Are there any pre-built tools or libraries for building a theme switcher with JavaScript?

    Yes, there are various JavaScript libraries and frameworks available that provide pre-built solutions for building theme switchers. Some popular options include Bootstrap, jQuery, and CSS frameworks like Bulma or Tailwind CSS, which offer built-in theming functionalities.

    5. Can I create more than just light and dark themes with a theme switcher?

    Absolutely! A theme switcher built with JavaScript can accommodate a wide range of themes beyond just light and dark. You can create custom themes with unique color schemes or even allow users to upload their own themes, providing a highly personalized browsing experience. The possibilities are virtually limitless.

    Subha Chanda is a talented technical author who specializes in writing on the JavaScript programming language and JavaScript games. Through his work, Subha seeks to share his knowledge and inspire others to explore the vast potential of JavaScript.
    IF YOU LIKE IT, THEN SHARE IT
    Advertisement

    RELATED POSTS