Frontend frameworks like VueJs, React and Svelte offer great flexibility in the development of UI components. The simplicity in which we can create components with dynamic properties offers the possibility to solve complex requirements with just a few lines of code.

If you have been using VueJs, you are probably aware of the limitation that prevented you to use props, data and computed properties within your component styles. Developers had to resort to the use of hacks to make styles dynamic, usually at the cost of more verbose code and untidy code.

Since the release of VueJs 3, we have a built-in solution that allows us the use properties directly within the <style> tag of our Single File Component (SFC). This feature is called v-bind in CSS and this post is going to cover in detail how to use this new feature, and what it actually means behind the scene.

I am a strong believer that an issue is best explained when the reader has full knowledge of the problem we are trying to solve. If you are aware of the issue and just want to see how to pass variables in CSS in Vue 3 you can jump to the next chapter named “v-bind in CSS in practice”, if on the other hand this is new to you and want to really understand this concept I suggest you read on.

Introduction – a real-life example

There can be many situations in which you may want to create dynamic CSS properties. In this section, we are going to provide a few scenarios that may require the use of dynamic variables and therefore provide context to be used in our next sections.

Button with multiple styles

This is probably the most common example that would require the use of variables in CSS. In this scenario our requirements are:

Create a button component that allow an user to specify its look and feel with the use of properties. The button woud accept a property of colour that will be used to define the component background color

The above requirement is extremely typical in component-based architecture. Even if simple, a fully developed component could require many properties to be configured. The most common solution for this issue is the creation of a “rigid” set of colours available and hardcode them directly using CSS classes, like “button-primary”, and “button-secondary” and then define the CSS for the specific style .button-primary: { background-color: red }

Dynamic Background image

A few years ago I was asked to create a component that would allow the creation of fancy cards. This card could be highly configurable and one of the requirements was to allow properties that defined its background image.

Many developers may think that a solution to this problem would be to use a <img> tag. Doing so would remove the need for a dynamic CSS variable, but unfortunately, this would not be semantically correct as a background image should be defined with CSS and if it is really just for decoration purposes. There are very important accessible distinctions between a background image and an image element as mentioned in this article on W3Docs.

Another possible solution for this requirement would be the use of JavaScript to dynamically change the value of the background image of a specific element. Even if this resolution would solve our needs, it would still create more code than we need and leave our components untidy.

Dynamic Sizing

In the third and last example, we are going to add some complexity to our requirements. Nowadays flexbox and grid have made layout and dynamic sizing much easier than it was a few years ago. There are still situations in which these two CSS features are not enough and some complex logic may still be required for us to achieve our needs.

A typical use case for the need for javascript and logic would be a page that needs to specify an element size depending on the number of items available on-page or set the height of a component depending on the amount of text that the page contains. I have had to develop both of these examples by hand and it was not a very clean solution as the framework would not allow me to do so.

V-bind in CSS in practice

It is now time to implement the above examples with the use of the new feature v-bind in CSS. The usage of the feature is very simple as it just requires you to use any property, computed property or data variable directly within the style section of your single file component.

The variable need to be wrapped into a v-bind method. So for example if we want to define a button component that accepts a colour property using the options API, we will write something like this:

<template>
  <button class="button">Click me</button>
</template>

<script>
export default {
    props: {
        colour: String
    }
}
</script>

<style>
.button{
    background-color: v-bind(colour);
}
</style>

The above code shows the simplicity and the power of this new feature. As you can see there is no need for any CSS preprocessor like LESS or SASS, as this new feature takes full advantage of CSS variables which we will cover later in this post.

Using dynamic CSS variables is not only possible while writing components using the options API, but it is also available with the newly introduced <script setup>. The example below shows how the above code can be translated into the script setup.

<template>
  <button class="button">Click me</button>
</template>

<script setup>
const props = defineProps({
  colour: String
})
</script>

<style>
.button{
    background-color: v-bind(colour);
}
</style>

The two examples shown above make use of simple properties. In the example below we are going to make use of a nested variable available within our data object.

<script>
export default {
    data() {
        return {
            styles: {
                backgroundColor: 'red',
                color: 'blue'
            }
        }
    }
}
</script>

<style>
.button{
    background-color: v-bind('styles.backgroundColor');
    color: v-bind('styles.color');
}
</style>

The use of nested properties is very similar to the simple example provided previously in this post. There are two main differences when using nested properties:

  • The variable name needs to be wrapped in quotes
  • The syntax used to access deep variables is the same one used in Javascript with the use of the “.” to delimiter the object structure.

Reactive CSS variable

It can not be a Vue post unless we talk about reactivity. The Vue Js framework is built on top of a powerful reactivity system, that allows it to be fully reactive to any change that a user action or change may incur. This reactivity can also be used to our advantage within our CSS.

<template>
  <button class="button" @click="changeBackgroundColor">Click me</button>
</template>

<script>
export default {
    data() {
        return {
            backgroundColor: 'red'
        }
    },
    methods: {
        changeBackgroundColor() {
            this.backgroundColor = 'blue';
        }
    }
}
</script>

<style>
.button{
    background-color: v-bind('backgroundColor');
}
</style>

In the code above our background colour will change from ‘red’ to ‘blue when the button is clicked.

How does v-bind in CSS works behind the scene

The last part of this article is going to go behind the scene and try to understand how this feature is working within the VueJs framework.

When I first learned about this feature, I has the impression that it would be a build time feature and would just work on the first render, hence not responsive. Luckily for you all, I was wrong. As you have seen from the previous chapter, this feature is fully responsive and works throughout the lifecycle of your component.

The way this feature works behind the scene is by defining CSS variables and assigning them to the root of the current component. If we take the example above in which we define a backgroundColor property, the code would look like this:

screenshot of v-bind in CSS from the Vue SFC playground

As the above image shows, the backgroundColor variable is actually being turned into a CSS variable named --472cff63-backgroundColor. The extra character in the name ensures that there is no conflict in the variable name.

The beauty of this implementation is that it enhances the development experience, as the variables are easily identifiable and easily changeable within the browser’s development tool. The following screenshot shows the how easy it is to grasp the variables:

Screenshot of the chrome developer tools that are showing the CSS variable being set from Vue JS

Conclusion

If we look back at the real-life example section that we used to start this post, we can start to understand how clean and flexible our solutions could be. Defining complex layout dimensions can easily be achieved using a simple computed property, or developing a set of button styles can be executed using a simple data property containing all the possible iterations.

I have personally been waiting for this feature for a very long time, as I have time and time again had to work around and write hacks to achieve very simple solutions. Even if you may think that you have no current need to use the v-bind in CSS feature, I can guarantee you that you will surely have need of it soon after its discovery.

I hope you find your own use of this great feature, and please feel free to post below a comment on real scenarios in which you used the above feature to help new readers.

🤞 Don’t miss these tips!

No spam emails.. Pinky promise!