Two and a half ways to use Vue component data in CSS

Two and a half ways to use Vue component data in CSS

30 Sep 2022 css javascript vue

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>

View demo

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>

View demo

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>

View demo

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:

return { text: { colour: 'red', weight: 'bold' } }

We can reference those deeper-level properties, like so:

<style scoped> p { color: v-bind('text.colour'); font-weight: v-bind('text.weight'); } </style>

View demo


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!