It's sort of cool to add a class to a component.
But the real fun begins when you can conditionally bind classes — turning them on and off as you wish.
In this article we'll cover:
There is a cool trick using the logical &&
(AND) that allows us to conditionally apply a class:
<template><spanclass="description":class="useTheme && theme">This is how you add dynamic classes in Vue.</span></template>
This is known as a guard expression.
When useTheme
is true
, it will set the class to whatever the value of theme
is.
But how does it work?
Here we have the variable useTheme
which is a boolean, and theme
is the value of the theme class.
In Javascript, the &&
(AND) operator will short-circuit if the first value is false
.
Since both values need to be true
in order for the expression to be true
, if the first is false
there is no point in checking what the second one is, since we already know the expression evaluates to false
.
So if useTheme
is false
, the expression evaluates to false
and no dynamic class name is applied.
However, if useTheme
is true, it will also evaluate theme
, and the expression will evaluate to the value of theme
. This will then apply the value of theme
as a classname.
This method is a bit clunky, so let's look at a better solution.
We can do a similar trick with ternaries.
If you aren't familiar, a ternary is basically a short-hand for an if-else statement.
They look like this:
const result = expression ? ifTrue : ifFalse;
Sometimes though, we'll format them like this for readability:
const result = expression? ifTrue: ifFalse;
If expression
evaluates to true
, we get ifTrue
. Otherwise we will get ifFalse
.
Their main benefit is that they are concise, and count as only a single statement. This lets us use them inside of our templates.
Ternaries are useful if we want to decide between two different values inside of the template:
<template><spanclass="description":class="darkMode ? 'dark-theme' : 'light-theme'">This is how you add dynamic classes in Vue.</span></template>
If darkMode
is true
, we apply dark-theme
as our class name. Otherwise we choose light-theme
.
The previous example could be re-written to use the object syntax instead:
<template><spanclass="description":class="{'dark-theme': darkMode,'light-theme': !darkMode}">This is how you add dynamic classes in Vue.</span></template>
Any time one of the values in the object evaluates to true
, we add the key to the classes. We can stuff as many class names in there as we want, which is great if we're using utility CSS like Tailwind:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
<!-- ... --><labelv-for="(answer, index) in question.answers":key="index"class="rounded-md py-3 px-5 border transition-colors duration-150":class="{'border-gray-300': !showResults && question.selected !== index,'border-gray-500 bg-gray-100':!showResults && question.selected === index,'border-green-500':showResults && question.correctAnswers.includes(index),'bg-green-100':showResults &&question.selected === index &&question.correctAnswers.includes(index),'border-red-500 bg-red-100':showResults &&question.selected === index &&!question.correctAnswers.includes(index),'cursor-not-allowed': showResults,'cursor-pointer hover:bg-gray-100 hover:border-gray-500':!showResults,}"><!-- ... -->
In this snippet I pulled from my course platform for Clean Components Toolkit, you can see we can have lots of complex logic that adds all sorts of different classes based on different conditions.
This component renders a question in a quiz, and these classes are responsible for highlighting when an answer is selected, correct, incorrect, or if it's disabled because the quiz is finished.
Sometimes the logic needed to decide what class name to apply is a little more complicated.
In these cases, it doesn't really fit that nicely inside of the template, and instead you want to put it into a computed prop:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
<template><!-- ... --><labelv-for="(answer, index) in question.answers":key="index"class="rounded-md py-3 px-5 border transition-colors duration-150":class="computedClasses"><!-- ... --></template><script setup>import { computed } from 'vue';const computedClasses = computed(() => ({'border-gray-300': !showResults && question.selected !== index,'border-gray-500 bg-gray-100':!showResults && question.selected === index,'border-green-500':showResults && question.correctAnswers.includes(index),'bg-green-100':showResults &&question.selected === index &&question.correctAnswers.includes(index),'border-red-500 bg-red-100':showResults &&question.selected === index &&!question.correctAnswers.includes(index),'cursor-not-allowed': showResults,'cursor-pointer hover:bg-gray-100 hover:border-gray-500':!showResults,}));</script>
This is a nice way to get things out of the template if you need to, but in this case we're not actually simplifying our code, just rearranging it.
There are lots of ways to add class names conditionally in Vue 2 and in Vue 3.
To apply more than one class at a time, you can:
I cover these in more detail, as well as generating class names on the fly, in this article on dynamic class names.