Two and a half ways to use Vue component data in CSS
30 Sep 2022
Compartmentalised CSS is a big part of component-based front-end development. Many frameworks, such as Vue and Svelte, are formed around single-file components (SFC), files which pertain to a single component and contain its template (markup), logic (JavaScript/TypeScript) and styling (CSS).
In this article I'll show a few ways - two and a half ways, to be precise - to use Vue component data within a component's CSS - even allowing for reactive CSS! We'll go through them in order of how well-known they are.
Method 1: style bindings
Anyone learning Vue learns style and class bindings pretty early on, so we won't spend too much time here. The basic idea is to harness Vue's data bindings for style
and class
attributes on HTML elements. So:
<template>
<p :style='{color: textColour}'>Hello, world</p>
</template>
<script setup>
import { ref } from 'vue'
const textColour = ref('red');
</script>
There, we tell Vue to pass an inline color
style to our paragrpah, but its value should be bound to our textColour
component variable. Any time our variable changes, the paragraph's colour will change too.
The problem with this approach is twofold. Firstly, using inline styles means muddying your HTML. Ideally, style information would live in style
tags or external CSS files. Secondly, it's element-specific; if I have another paragraph that I want to give the same treatment, I have to repeat the trick.
Method 1.5: CSS vars via style bindings
I'm calling this method 1.5 because it's really a spin-off from method 1, style bindings, but it involves a little more cleverness.
This time, we'll harness CSS variables together with Vue bindings.
<template>
<p :style='cssVars'>Hello, world</p>
</template>
<script setup>
import { ref } from 'vue'
const cssVars = {
'--text-colour': 'red',
'--font-weight': 'bold'
}
</script>
<style scoped>
p { color: var(--text-colour); font-weight: var(--font-weight); }
</style>
This is pretty cool, but doesn't address any of the concerns with method 1 - we're still using inline styles (allbeit passing variables rather than explicit styles) and it's still element specific, because our variables are scoped to the element only.
Method 2: v-bind within styles
And now for the main event. As of Vue 3.2+, we can reference component variables directly within our SFC's style
tag. This is a game-changer. Let's take a look:
<template>
<p>Hello, world</p>
</template>
<script setup>
import { ref } from 'vue'
const textColour = 'red';
</script>
<style scoped>
p { color: v-bind(textColour); }
</style>
See the v-bind()
call within our CSS? Sweet!
Bear in mind that, unlike when using v-bind on HTML elements, we can't shortcut this via :
syntax, i.e. :textColour
would not work here.
We can even drill into objects. Say we instead had our component logic export this:
We can reference those deeper-level properties, like so:
---
So there you have it - Vue has you covered in a number of ways when you want to use component data in your CSS, and even have reactive CSS.
Did I help you? Feel free to be amazing and buy me a coffee on Ko-fi!