How I Theme My React App With Sass

How I Theme My React App With Sass

And with the power of mixins
Ferenc AlmasiLast updated 2021 November 11 • Read time 7 min read
Leveraging sass functionality such as maps and mixins can help us theme our react app as we like. The best part? - It works by switching one single class…
  • twitter
  • facebook
React

Before any coding, I’ve been always starting my projects with a clear design — or at least a rough prototype — in mind. Probably my biggest and still ongoing diet management application is no exception from this.

However, this time, when I finished the designs for the app, I felt like something was missing. I started with a light, white-based design that resembled the sleek design of macOS but I was always a fan of dark themes.

So I started to experiment with different styles. Eventually, I created two separate designs; a light and a dark theme. I really liked the dark theme. It helps both the longevity of my screen as well as my eyes in dark conditions. But since I originally started with the white design, it felt like it is as much as part of the application as the dark one. I decided; why not keep both and create a theme chooser?

It works on a simple principle: depending on a class on the html tag, we style elements differently.

Copied to clipboard!
.theme-light body { background: #FFF; }
.theme-dark body { background: #000; }
styles.scss

But how do we prevent to write out the same styles for every theme? This is where mixins will come into place. But first, let’s start by creating the color palette for them.


Setting Up The Color Palette

The color palette will hold every color for each theme. To separate them from my main styles, I’ve created a partial, called _color-palette.scss, and pulled it inside my main sass file. Inside it, we will have a $themes variable which will hold a list of map: a map for each theme.

Copied to clipboard!
$themes: (
    light: (
        color-background: #FAFAFA,
        color-card: #FFF
        .
        .
        .
    ),
    dark: (
        color-background: #37474F,
        color-card: #212121
        .
        .
        .
    )
);
_color-palette.scss

Maps in Sass are a powerful way to hold key-value pairs. We can easily look up values by its corresponding key and we can get a value by using the built-in map-get function. For example, to get the background color for the light theme, we would have to use two map-get functions in conjunction:

Copied to clipboard!
// Get value from nested maps
map-get(map-get($themes, 'light'), 'color-background');
_mixins.scss

First, we get the map for the light theme, then we wrap everything inside another map-get to get the specific key, which in this case is the color-background variable.

Now, this is no dynamic by any means. It would be insane to write this out to change the color of a UI element not to mention this only covers one theme. To easily grab a color no matter what theme is active, we can create a handy mixin for it.


Making The Mixin

This will be the core handler that will generate styles for each theme we have. In order to know how to create the mixin, let’s see what we would like to have in the end:

Copied to clipboard!
// Get the color-background property from the active theme map and apply its value to the "background" css property
body {
    @include theme-aware('background', 'color-background');
}
styles.scss

We want to have a mixin called theme-aware to which we can pass two values:

  • One for the CSS property that we would like to change
  • One for the name of the key inside our color-palette

In the example above, it should result in the following: background: #FAFAFA; or background: #37474F. But how do we know which one to apply? And what if we want the change to happen seamlessly without a page reload?

We don’t really have the power to switch styles inside CSS, so instead, we can create a separate rule for each theme. Say in case the html tag has a .theme-light class, we apply the styles corresponding to the light theme. If we have a .theme-dark class, we apply the ones associated with that theme.

With this in mind, we can create the mixin:

Copied to clipboard!
/**
 * theme-aware - Change color of a css property based on the currently active theme
 *
 * @param  {key}     CSS property
 * @param  {color}   Color name defined in the themes under _color-palette.scss
 *
 * @example - @include theme-aware('background', 'color-background');
 * @returns - background: #FFF;
 */
@mixin theme-aware($key, $color) {
    @each $theme-name, $theme-color in $themes {
        .theme-#{$theme-name} & {
            #{$key}: map-get(map-get($themes, $theme-name), $color)
        }
    }
}
_mixins.scss

It accepts a $key and a $color. Inside the mixin, we loop through each theme using the @each control and for each theme, we add the following rule:

Copied to clipboard!
.theme-<name of the theme> & { ... }

// So in the end we will have
.theme-light & { background: #FAFAFA; }
.theme-dark & { background: #37474F; }
styles.scss

Inside the rule, we can then use the passed $key with interpolation and the two map-get functions to get the color from the theme.

Now if we use the mixin, it will generate two different rules for the two themes:

Copied to clipboard!
body {
    @include theme-aware('background', 'color-background');
}

// It will generate the following rules:
body {
    .theme-light & { background: #FAFAFA; }
    .theme-dark & { background: #37474F; }
}

// After compiling scss down to css, we get the following
.theme-light body {
    background: #FAFAFA;
}

.theme-dark body {
    background: #37474F;
}
styles.scss

We can leverage the element & selector in SCSS to apply styles to the element if it is inside a parent which matches the theme selector.

Looking to improve your skills? Check out our interactive course to master React from start to finish.
Master Reactinfo Remove ads

Pulling Everything Into React

Now that we have everything, all we need to do is switch a class on the body and that will instantly change the whole theme of the application:

Switching themes by changing the class name on the html element

To put this into React I’m using a select which updates the user preferences as well as switches class on the html.

The UI

I defined the available themes in an array and loop through it to create an option for each. The component is coming from the Ant library and whenever the value changes, it calls the changeTheme function which is responsible for switching themes.

Copied to clipboard! Playground
const themes = [
    'light',
    'dark'
];

<Select defaultValue={user.theme} onChange={changeTheme}>
    {themes.map((theme, index) =>
        <Option value={theme} key={index}>{theme}</Option>
    )}
</Select>
component.jsx

The controller

The function gets the value of the selected option and uses it to update both the user’s default theme and the class on the HTML element:

Copied to clipboard! Playground
changeTheme = (theme) => {
    user.theme = theme;
    
    document.documentElement.className = '';
    document.documentElement.classList.add(`theme-${user.theme}`);
    
    alert('Theme updated...');
}
controller.js

The matter of fact is that it can be done with anything not just React. The key part here is leveraging sass functionality such as maps and mixins for generating the styles for each theme.

Changing the theme in the React app
Changing the theme in the React app

Summary

With this, you can create as many themes as you want. All you need to do is create a color palette for a new theme and use the theme-aware mixin for the elements that you want to style. You add a new option for the theme into the select and you’re all set. 🎨

Thank you for taking time to read this article, happy styling!

Want to take your CSS to the next level? Learn how to improve its the performance and scalability:

10 Best Practices for Quickly Improving Your CSS
  • twitter
  • facebook
React
Did you find this page helpful?
📚 More Webtips
Frontend Course Dashboard
Master the Art of Frontend
  • check Access 100+ interactive lessons
  • check Unlimited access to hundreds of tutorials
  • check Prepare for technical interviews
Become a Pro

Courses

Recommended

This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.