Skip to main content

Building Design Systems with CSS Variables

Building Design Systems with CSS Variables

For organizations that have to design for multiple platforms, establishing a set of design standards and repeatable components (what we call Design Systems) is becoming increasingly important. In this article, we will break down how to create Design Systems with CSS Variables, a powerful browser API that helps developers create repeatable style components so that the organization’s brand and user experience remain consistent across products. 

What is a CSS Variable?

CSS Variables (also known as CSS Custom Properties) are a web standard response to a need that is often present when developers use stylesheets: re-using a specific value across multiple definitions. CSS Pre-compilers and JavaScript techniques had initially tried to solve this with multiple techniques. While these tools did help developers increase productivity, the variables they used were inherently static. Fortunately, the release of Chrome 49 gave way to the browser standard, offering us a much better solution with CSS Variables. See the browser chart support.

definition of a custom property is This is an example of a definition of a custom property done inside any CSS selector. This must always be a key + value pair in the syntax of --name: value`.

It is important for us to understand the basics of the CSS properties set. There are two key points here: defining a custom property and using it with the var function inside your code.

The definition of a custom property is done inside any CSS selector. This must always be a key + value pair in the syntax of –name: value`.

Descendants of that selector will have access to the property and will be able to overwrite them.

`:root` example. Synonym for the HTML tag, has higher selector specificity.

We can add different types of values that are incredibly diverse, including numeric values, colors, and property values.

These values will always be passed untouched and indifferent to the intention of use. Let’s say you want to use the custom property weight as a height measurement. It will be invalid as size measurements require a unit, such as `px`, `rem`, etc…

You can attach them to a selector `:root`. This is a synonym for the HTML tag, so it will be globally available with a higher selector specificity.


Using CSS Variables

Using the custom property names as values in a CSS property will give you an error. To isolate the use of custom properties, we use the `var()` function, passing the property name as defined. CSS Variables are very robust, so we can mix this with other CSS functions such as `calc()`, `clamp()`, and as partial parts of a complete property.

Example of how to use the `var()` function, passing the property name as defined. You can mix this with other CSS functions such as `calc()`, `clamp()`, and as partial parts of a complete property.

What is a Design System?

Design systems are defined sets of guidelines and repeatable components that help developers simplify the creation of new components. Doing so helps development teams accomplish a consistent look and feel across products and gives way to enhanced creativity and productivity. This sounds great, but when implementing on the code side it can become messy for several reasons, including the huge number of values that can come from a Design System, the resulting need to keep track of them on your own, and tweaks you have to make during development. Even the simplest UI can lead to many small, sometimes noticeable discrepancies that can give the page an odd look. This is why design systems should not only include the ‘what’, but also the ‘how’ and ‘why.’

Example of noticeable design discrepancies.

Creating a Design System using CSS Variables

The idea is that you shouldn’t have standalone values used in your CSS. Always (in the scope of sense) use variables instead. Let’s define a button with variables instead, so we don’t have values floating around:

No standalone values used in CSS. Should use variables instead. This an example of a button with variables.

We will keep only keywords and variables, this way we can tell this button is primary and has a regular size. Also, if for some reason we changed the variables, they will automatically update everywhere instead of having to find and replace each instance where the specific measure was used.


Some properties that are necessary to define for your system are:

Colors, Font Size, Spacing Border Radius, Line Height, and Z Index are necessary to define.

  • Colors
  • Font Size
  • Spacing
  • Border Radius
  • Line Height
  • Z Index


Doing this allows you to keep track of the different design options and allows you to see each of them and their corresponding values in the browser. In other words, you are using code as documentation.

An example of this is having named z-indices; this way we can tell how spinners should be over everything no matter what, and that overlays will hide the navs even if it has some importance. This also speaks about how the interactions should work.

For colors, intentions are more important than the actual values. This will become important because we will be able to override this and create themes, so ‘primary’ is a better name than ‘green’ for our button.


Automation & Extension

Current technologies also are aware of these situations and come with their own solutions. For this part, we’ll be using React to showcase the different approaches. But as CSS Variables are a web standard, this solution can also be applied to Vainilla, Svelte, Vue, and even pre-processors such as SASS.

CSS-in-JS for Automation

Color example using React.

Although having all the different properties predefined can make a wonderful development experience, creating this experience from scratch can be overwhelming as we try to choose the right sizes and write them all into a gigantic base stylesheet. Now that we can create CSS dynamically, we can solve this by simply creating the sizes as a JS Object and parsing this into a globally available stylesheet.

This can be done in a few steps. First, define the values as an object. This will be important as we’ll be naming the values already in place and have techniques to iterate over objects. Second, we’ll create a function that parses that into valid custom properties. Finally, we’ll throw all of this in styled-components into a globally available stylesheet. See this gist with a complete implementation.

1. define the values as an object. 2. Create a function that parses that into valid custom properties. 3. Put all styled-components into a globally available stylesheet.


CSS Variables VS Theme Providers

Users of design systems that use solutions like Theme Providers (wherein all the attributes are passed as JavaScript objects or functions) can start using CSS Variables Design Systems to simplify their codebase, further reducing the heat on JavaScript load.

Java script simplification.


Themes and Dark Mode

CSS Variables are defined in a global scope, allowing us to enable “Themes.” With these, the content on your site can be displayed in multiple palettes (think MySpace here) and allows you to detect and/or enable the option for the user to choose dark mode. This can be handled with classes and media queries. See the following examples:

example of a dark theme in CSS.

Here, we use CSS only to determine that the user prefers a dark color schema. If that CSS media feature is not supported or the user prefers a light scheme, the default version of the website will be used. This can be used to extend any properties to those that fit the schema better.

It’s recommended that the default theme is the light one. In the case that something fails, a more natural experience is provided to the user.

Remember the importance of having a CSS Code that relies on these variables and keywords so it can update correctly.





Example of customized theme.

Here, with JavaScript, we can set a class into the body, allowing us to change the mode or theme to a different set of colors. This works because having a class to define the properties gives us an overwrite of the current properties.

Now imagine that you have not only defined a `dark` theme but also a `blueShades` or `pride` theme.

You can allow your user to choose and your work is simply to overwrite the intentions to values that match the desired theme.



What’s next?

Building a robust design system can help your organization create beautiful, harmonic, and reliable interfaces. Now that you understand the power and value behind creating your own design system using CSS Variables as its engine, it’s up to you what you want to create.


New call-to-action