JSNow Logo Dark Theme
Technology Icon

Vue Dynamic CSS Variables Using v-bind In CSS v3.2

Creating a Real-Time QR Code Scanner With Vanilla JavaScriptโ€Š Part Two Banner Image

This articles will be about two new features recently added to Vue v3.2

  • State Driven CSS (using v-bind inside CSS)
  • Script tag setup attribute

Recently added into Vue v3.2 is something called "State-Driven CSS Variables", this allows us to easily use reactive variables & data object values inside our styles in our SFCs (Single File Components).

So you can write an SFC (Single File Component) that looks like this ๐Ÿ‘‡

App.vue
<template>
  <div>
    <input type="text" v-model="color" />
    <div class="user-input-color">
      {{ color }}
    </div>
  </div>
</template>
 
<script>
export default {
  data: () => ({
    color: 'white'
  })
}
</script>
 
<style scoped>
.user-input-color {
  background-color: v-bind(color)
}
</style>

Using The Composition API

How can we create a version of this application using the Vue 3 composition API? this is a lot easier to do than you may think. Instead of using the data object, we will be using reactive variable using ref().

App.vue
<template>
  <div>
    <input type="text" v-model="color" />
    <div class="user-input-color">
    	{{ color }}
    </div>
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
  
const color = ref('white')
</script>
 
<style scoped>
.user-input-color {
  background-color: v-bind(color)
}
</style>

Now, this is even easier to read and understand you may have noticed the "setup" attribute in the script tag. The "setup" attribute is also a new addition to Vue v3.2. "setup" is just some syntactic sugar that makes using the Composition API even easier and cleaner to use, so instead of writing this.

App.vue
<script>
  export default {
    setup() { 
      // Your code here :) 
    }
  }
</script>

We can write it like this ๐Ÿ‘‡

App.vue
<script setup>
// Your code here :) 
</script>

When Would I Use State-Driven CSS?

A great use case for State-Driven CSS Variables would be to handle form validation. When your users enter unwanted or incorrect data into your form we want our page styles to display that information visually to our users, so they know something went wrong.

App.vue
<template>
  <h3>Form Validation Example</h3>
  <p>
    Name is required input & Lucky Number must be a nubmer
  </p>
  <div class="validation-check">
    <div v-if="!errors.length">
      <h3>Success!</h3>
      <p>This form is valid. No errors ๐Ÿ˜๐Ÿ‘</p>
    </div>
    <ul v-else>
      <li v-for="(error, key) in errors" :key="key">
        {{error}}
      </li>
    </ul>
  </div>
  <form @submit.prevent="handleSubmit">
    <input type="text" v-model="name" placeholder="Name">
    <input type="text" v-model="luckyNumber" placeholder="Lucky Number">
    <input type="submit" value="Submit">
  </form>
</template>
 
<script setup>
import { ref } from 'vue'
 
const name = ref('')
const luckyNumber = ref('')
const errors = ref([])
const validationState = ref('lime')
 
const handleSubmit = () => {
  errors.value = []
 
  if (!name.value.length > 0) {
    errors.value.push('Name is required')
  }
 
  if (luckyNumber.value.match(/D/g)) {
    errors.value.push('Lucky number must be a number')
  }
 
  if (errors.value.length) {
    validationState.value = 'red'
  } else {
    validationState.value = 'lime'
  }
}
</script>
 
<style scoped>
.validation-check {
  padding: 2rem;
  background-color: v-bind('validationState')
}
 
* {
  font-family: Arial, Helvetica, sans-serif;
}
 
form {
  display: flex;
  flex-direction: column;
  margin-top: 50px;
}
input {
  margin-bottom: 5px;
  padding: 10px;
}
</style>
Buy Me A Coffee JSNow