DEV Community

Cover image for Dynamic Brand theming using CSS variables
mathumitha
mathumitha

Posted on

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.

Checkout mockup image

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);
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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.

  1. https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties#basic_usage
  2. https://electerious.medium.com/the-power-of-css-variables-6c4e4ebaf279

Discussion (4)

Collapse
wireless25 profile image
Stephan Simonett

I have to do something similar, but instead of having user-generated themes, I'm building an app that different companies will use. We'll host one instance of the app and load the config depending on the request URL. With CNAMEs, we'll point the company domains to the same app instance on the server. Like this, it's easy to have a dedicated config per company. For the theming, I want to go the same as you explained here. The config will hold values for brand-specific colors, image URLs from the CDN, and whatnot. Then use setProperty client-side to populate the CSS variables with the values from the config. Pretty neat, and nice to know other people do it the same way 😅

Collapse
mathumitha profile image
mathumitha Author

Hey, This is nice. Asking this out of curiosity. Are you maintaining any app server which serves the configuration or you are using any lambda function which will return the configuration?

Collapse
wireless25 profile image
Stephan Simonett

We run a Nuxt app on a server cause we need SSR for authentication. This way, I can use the serverMiddleware Nuxt provides. This is basically the node process the Nuxt app itself is running on, so no need for an additional server, pretty nice. Nuxt docs

The config is not that fancy, just some values for colors, some translation strings, and some image paths. I "hard code" this as an object directly in my endpoint in the serverMiddleware. If this scales, like more complexity or more companies (now only 3), I will maybe externalize the config, but for now, this is perfectly fine.

Thread Thread
mathumitha profile image
mathumitha Author

That's awesome 👍