Dynamic Brand theming using CSS variables

Recently, I got to work on an e-commerce checkout page builder (No code tool) where the merchants can change the theme according to their brand. The merchants can configure their brand colour and secondary colour to various elements like buttons, containers, texts, etc. This configuration will be fetched using APIs and applied to checkout pages on rendering. I was exploring various approaches such as SASS/LESS/Stylus variables, CSS-in-JS libraries and CSS variables for applying the theme. After a deep exploration, I ended up using CSS variables. In this article, I would like to explain the pros and cons of each approach and how I ended up using CSS variables.

SASS/LESS/Stylus variables:

CSS preprocessors are scripting languages that allow developers to write DRY styles using variables, functions, mixins, etc. These DRY styles would be converted into raw CSS styles in compile time. If we are aware of all theme-related information during compile time, we can easily map them to these variables and achieve theming. As the checkout has to allow the merchants to change the theme dynamically in run time, we cannot go with this approach.

CSS-in-JS libraries:

There are many CSS-in-Js libraries available in the market such as styled-components, emotion, glamorous, etc. These provide extensive theming support. However, these libraries require <ThemeProvider /> which has to be wrapped over the app in order to provide theming context. Vendor lock-in is another disadvantage of using this. We will not be able to easily switch to a different approach in the future. As we got used to the traditional CSS approach, the learning curve is also steep.

CSS Variables:

CSS variables a.k.a custom properties allow us to change the values dynamically in the run time using Javascript. We can use var()to use a variable in the references of the stylesheet. You can assign the value of CSS variable either in CSS or javascript. Many latest browser versions support CSS variables. As CSS variables are supported by native CSS and the learning curve is also shallow, I preferred CSS variables for my theme-able system.

Let’s create a simple checkout page that contains the shipping address section, the payment section and the cart section. The merchant would be able to configure brandColor, secondaryColor and bodyBackgroundColor for these sections.

Step 1 — Mapping the variables to check out elements

Let’s map each variable to the respective checkout elements.
brandColor- This is used for primary buttons, logo and border colours
secondaryColor — This is used in the apply coupon input group
bodyBackgroundColor- This is applied as a background colour to the main container.
Checkout mock ip image with pointers

Step 2 — Using the CSS variables in the stylesheet.

To assign a CSS variable to a property, we have to use var().

Let’s have a look at the selectors which use brandColorvariable. The value for this variable will be set using javascript during run time.

secondaryColor variable is used for the apply coupon button.

bodyBackgroundColor is applied to the main container of the application.

Step 3 — Creating Merchant configuration JSON

Our theme builder configuration will be exposed via API from the server. The configuration JSON will be looking something like this

In order to demo, let’s mock the server response with static JSON. getMerchantConfigfunction will return a promise which resolves the merchant configuration using the merchantId argument.

Step 4 — Setting values for CSS variables in Javascript

Now, let’s see how the variables are set in Javascript. As the variables are used across the stylesheet, let’s set the variables in the root element.

const root = document.querySelector(':root');
root.style.setProperty('--brandColor', merchant.brandColor);
root.style.setProperty('--secondaryColor', merchant.secondaryColor);
root.style.setProperty('--bodyBackgroundColor', merchant.bodyBackgroundColor);

Now, we have to get the theme configuration for the merchant. Let’s say Merchant 1 is active. we have to call getMerchantConfig function by passing merchantId merchant1.

const setTheme = async () => {
  const merchant = await getMerchantConfig('merchant1');
  const root = document.querySelector(':root');
  root.style.setProperty('--brandColor', merchant.brandColor);
  root.style.setProperty('--secondaryColor',     merchant.secondaryColor);
  root.style.setProperty('--bodyBackgroundColor', merchant.bodyBackgroundColor);
};
setTheme();

The final Js code will be looking like this.

That’s all, We are done with it 😎. You can see the working demo in the codepen. You can play around by passing different merchantIds to getMerchantConfig function. You can also try configuring other properties such as font-size, font-family, etc.

Conclusion:

Theming is much more simplified using CSS variables. There is no vendor lock-in. CSS variables are supported by native CSS and have great browser compatibility. It’s the best fit for my feature. CSS variables have much more potential other than theming. It reduces plenty of repetitive tasks. You can give it a try. I’m attaching a few good resources here.

26