DEV Community

Milos Protic
Milos Protic

Posted on

UI Theming with CSS Variables

Originally published on my-blog

This article is about using CSS variables to switch the theme on our web application or site. It assumes that you've read my previous article, CSS Variables Cheat Sheet or that you have some knowledge about the feature.

What will we build?

Below is the final result of the code written in this article. To achieve it, we will use some basic HTML, CSS and JavaScript operations.

final-result

As you can see, on the left side we will have configurable options for our theme. I think that changing the background color, color, and font is enough to see and understand how the theme switching can be done for our web site or an application.

The process is straightforward. First, we will build the HTML layout, apply CSS to it with the default theme variables and attach a couple of event handlers to dynamically update the theme.

Note that the JS code is written in the next-generation of JavaScript, therefore make sure that you are using the latest browser which supports it.

HTML Setup

Default Themes Switcher

The circles on the top left side will be responsible for switching the predefined theme assigned to each of them. We will build three themes as predefined ones and allow the dynamic coloring via color inputs which we will see later in this article. The default color schemes will be green (Vue), blue (Facebook) and blue (Twitter). To create the buttons, for example, we can use three span elements.

Note that you could use a button or input element, it doesn't matter. There is no specific reason for me to use the span element. It's just an example.

Ok, back to the markup. It looks like this:

<span class="btn vue-green" data-bg-color="#42b883" data-color="#35495e">&nbsp;</span>
<span class="btn fb-blue" data-bg-color="#3b5998" data-color="#8b9dc3">&nbsp;</span>
<span class="btn tw-blue" data-bg-color="#0084b4" data-color="#00aced">&nbsp;</span>
Enter fullscreen mode Exit fullscreen mode

Since we are using a span element, we need to store the predefined colors somewhere. The way to do this is to use data attributes. The values from these attributes will be used for our theme which we will see later in this post.

TIP: You could also set these through JavaScript on page load to remain clean. The values could be, for example, defined as a CSS variable and when the page initially loads you could read them and set each span data attribute accordingly.

Font Switcher

Font switcher will be a simple select element with three option elements within. Each option will have the value which will be used for the font-size update:

<select>
    <option value="12">12px</option>
    <option value="15" selected>15px</option>
    <option value="25">25px</option>
</select>
Enter fullscreen mode Exit fullscreen mode

Dynamic Coloring

For the user-defined theme colors, we will take advantage of the input element with a type of color. This is pretty neat and enables us to have a fully functional color picker on the web page.

<label for="bg-color">Background:</label>
<input type="color" id="bg-color">
<label for="color">Color:</label>
<input type="color" id="color">
Enter fullscreen mode Exit fullscreen mode

The full left side section now looks like this:

<aside>
    <h1>Theme Switcher</h1>
    <h3>Defaults</h3>
    <span class="btn vue-green" data-bg-color="#42b883" data-color="#35495e">&nbsp;</span>
    <span class="btn fb-blue" data-bg-color="#3b5998" data-color="#8b9dc3">&nbsp;</span>
    <span class="btn tw-blue" data-bg-color="#0084b4" data-color="#00aced">&nbsp;</span>
    <h3>Font Size</h3>
    <select>
        <option value="12px">12px</option>
        <option value="15px" selected>15px</option>
        <option value="25px">25px</option>
    </select>
    <h3>Dynamic Color</h3>
    <label for="bg-color">Background:</label>
    <input type="color" id="bg-color">
    <label for="color">Color:</label>
    <input type="color" id="color">
</aside>
Enter fullscreen mode Exit fullscreen mode

Variables Setup

Since the HTML configurable section is now complete, it's time for us to set the CSS variables and their default values. We will do this on the :root pseudo-class:

:root {
    --primary-color: #42b883;
    --primary-bg-color: #35495e;
    --primary-font-size: 15px;
    --color-white: #fff;
}
Enter fullscreen mode Exit fullscreen mode

This enables us to reuse the variable wherever we need the specified color or font. The default theme will be green, for example.

Using The Variables

Let's say that we want to change the background-color on the body element, the color on the main element and the font-size on each p element.

Our css should look like this:

body {
    /* removed for brevity */
    background-color: var(--primary-bg-color);
}
main {
    /* removed for brevity */
    color: var(--primary-color);
}
p {
    font-size: var(--primary-font-size);
}
Enter fullscreen mode Exit fullscreen mode

The CSS variable is set to an element by using the var function. The value of the CSS property is resolved and taken from the CSS variable. This is very neat because whenever we change the variable, the value for these properties will be updated.

JavaScript Setup

Ok, now we are ready to introduce the JavaScript part. Without it, theme switching wouldn't be possible. We need a way to change the values of our CSS variables, and this is done with a little bit of JavaScript code. A couple of simple steps and we will be done:

  1. Create the logic to update the CSS variable
  2. Find the element we need
  3. Attach the event handler
  4. Execute the code responsible for the variable update

The function responsible for the variable update:

const handleThemeUpdate = (cssVars) => {
    const root = document.querySelector(':root');
    const keys = Object.keys(cssVars);
    keys.forEach(key => {
        root.style.setProperty(key, cssVars[key]);
    });
}
Enter fullscreen mode Exit fullscreen mode

In a nutshell, this function takes an object as a parameter and for each key updates the corresponding CSS variable defined on the :root pseudo-class. To achieve this, we need to define the object in a way where each key represents the CSS variable name and each key value represents the actual CSS value we want to apply.

Example:

{
    '--primary-bg-color': 'green'
}
Enter fullscreen mode Exit fullscreen mode

Next, we need to find the elements and attach the event handlers:

const themeSwitchers = document.querySelectorAll('span');
const fontSwitcher = document.querySelector('select');
const dynamicInputs = document.querySelectorAll('input');

themeSwitchers.forEach((item) => {
    item.addEventListener('click', (e) => {
        handleThemeUpdate({
            '--primary-bg-color': e.target.getAttribute('data-bg-color'),
            '--primary-color': e.target.getAttribute('data-color')
        });
    });
});

fontSwitcher.addEventListener('change', (e) => {
    handleThemeUpdate({
        '--primary-font-size': `${e.target.value}px`
    });
});

dynamicInputs.forEach((item) => {
    item.addEventListener('change', (e) => {
        const cssPropName = `--primary-${e.target.id}`;
        handleThemeUpdate({
            [cssPropName]: e.target.value
        });
    });
});

Enter fullscreen mode Exit fullscreen mode

Hopefully, now you can see the connection between the HTML, CSS, and JS. Our data attributes are read when the user clicks on a span element and the value from it is set to the corresponding CSS variable.

Also, when a user changes the value of the color-picker element or selects a new font size, the selected value is set to the corresponding CSS variable.

If you wish to play around with the code a little, do check out the live fiddle.

Thank you for reading, and see you in the next post.

Further Reading

If you haven't read my previous post, CSS Variables Cheat Sheet, go and check it out.

If you are interested in CSS flexbox module, check out this article. It provides simple explanations and fun ways to learn how to use it.

Top comments (0)