August 9, 2023

My Favorite Underrated Vue 3 Feature

When it comes to JavaScript frameworks, it's common to focus on well... the JavaScript stuff. But of all the features in Vue 3 that I love, mine is actually on a CSS feature (with some JavaScript 😜).

CSS + User Preferences == Chaos

One of the biggest issues in building web applications is how we manage custom styles. A common example of this is the definition of themes in applications. The simplest example of this is the popularity of light and dark themes.

Historically speaking, typically user preferences and/or desired customizations of an application are managed through:

  • Predefined CSS themes - Light, Dark, Solarized, Dracula, etc.
  • Limited configuration - Settings for users to set specific styles that developers are willing to maintain (e.g., font size, font family, etc.)
  • Custom CSS Injection - A place for users to add their own CSS into the application

Part of the reason we've been confined to this approach is because maintaining custom styles can be incredibly difficult to do at scale. And while CSS is incredibly powerful, without a thorough understanding of fundamental principles and architecture, the cascading effects can result in unintended bugs.

While this has worked for many years, it has always left me wondering whether there could be a better way.

How to manage dynamic CSS in Vue 3

Let's say that you want the user to be able to select any color they want for all h1 elements in your application.

One way we might accomplish this is to inline our styles where it makes sense.

<script setup>
const textColor = ref('#000')
</script>

<template>
  <h1 :style="`color: ${textColor}`">This is my title!</h1>
  <input v-model="textColor" type="color" />
</template>

However, as you might imagine, one of the limitations of this approach is that you'd need to track and manually manage any element that is dependent on the reactive textColor property.

Not very scalable right?

Dynamic CSS done right

In Vue 3, there is a new concept of using v-bind within your CSS.

Taking the previous example, here's what it might look like:

<script setup>
const textColor = ref('#000')
</script>

<template>
  <h1>This is my title!</h1>
  <input v-model="textColor" type="color" />
</template>

<style>
h1 {
  color: v-bind(textColor)
}
</style>

And believe it or not, everything just works as expected! πŸŽ‰

For a live example, check out this playground demo.

Wait... how does it work?

Now, some of you may be feeling skeptical, but one of my favorite things about Vue is that the framework tries to leverage existing frontend technologies to accomplish seemingly new concepts. And this continues to be true for the v-bind in CSS.

Here's an example what the rendered output might look like:

<h1 style="--3d65ef30: #2f9836;">This is my title!</h1>
<input v-model="textColor" type="color" />
h1 {
  color: var(--3d65ef30);
}

Underneath the hood, Vue is doing the following:

  1. Creates a unique CSS Variable that is inlined on the HTML element
  2. Assigns the unique CSS variable to the correct CSS styles
  3. Uses its reactivity system to dynamically update the variable value so that everything works exactly as expected

And just like that, unlimited style preferences are unlocked while keeping maintenance to a minimum! πŸ’ͺ

Next steps

When building your next app, I highly recommend giving this a try and wowing your clients with what's possible with this level of customization.

And for those who want to learn more, check out the docs for v-bind in CSS.