VueJS 3 tutorial – Binding CSS classes and inline styles
verified on 2 September 2026 · 4 min
:class takes an object whose keys are class names and whose values are conditions, :style takes an object of CSS properties written in camel case. The static class attribute and the dynamic :class live side by side: Vue merges them.
class and style are two special attributes: on top of strings, v-bind accepts objects and arrays for them. That is what lets you reflect the state of the application in its appearance without touching the DOM by hand.
Colour swatches
Let us replace the words “Bleu” and “Rouge” with swatches in the actual colour. First store a hex code rather than a name:
<script setup>
const variants = ref([
{ id: 2234, color: '#2563eb', image: '/images/t-shirt-bleu.svg' },
{ id: 2235, color: '#dc2626', image: '/images/t-shirt-rouge.svg' }
])
</script>Then bind the background colour:
<div class="variants-wrapper">
<div
v-for="variant in variants"
:key="variant.id"
class="color-circle"
:style="{ backgroundColor: variant.color }"
@mouseover="updateImage(variant.image)"
></div>
</div>Two round swatches appear, one blue and one red, and hovering still changes the image.
Camel case or kebab case
The object passed to :style is a JavaScript object. CSS property names are therefore written in camel case:
<div :style="{ backgroundColor: variant.color }"></div>Writing background-color without quotes would be read as a subtraction. Kebab case is still available, inside quotes:
<div :style="{ 'background-color': variant.color }"></div>Both forms produce the same result. Pick one and stick to it.
Moving the style out of the template
Once the properties pile up, the template becomes unreadable. Declare the object in the script:
<script setup>
const styleTitre = ref({
color: '#111827',
fontSize: '28px',
fontWeight: '700'
})
</script>
<template>
<h1 :style="styleTitre">{{ product }}</h1>
</template>An array combines several objects, the later ones winning over the earlier ones:
<div :style="[styleBase, styleSurcharge]"></div>Binding a class
On to the button. When the product is out of stock, it has to be both disabled and visibly disabled.
Start with the disabled attribute, bound as in chapter 2:
<button class="button" :disabled="!inStock" @click="addToCart">
Ajouter au panier
</button>The button no longer responds to clicks, but nothing shows it. Add the grey class, on the same condition:
<button
class="button"
:class="{ disabledButton: !inStock }"
:disabled="!inStock"
@click="addToCart"
>
Ajouter au panier
</button>In the object passed to :class, the key is the class name and the value is the condition. When !inStock is true, the disabledButton class is added, otherwise it is removed.
class and :class live side by side
The button carries both class="button" and :class="{ … }". Vue does not pit them against each other: it merges them.
<!-- écrit dans le gabarit -->
<button class="button" :class="{ disabledButton: true }">
<!-- rendu dans la page -->
<button class="button disabledButton">Keep the fixed classes in class and the conditional ones in :class.
Several conditional classes
The object takes as many entries as you need:
<div :class="{ actif: estActif, 'en-erreur': aUneErreur, masque: !visible }"></div>A class name containing a hyphen has to be quoted, for the same reason as kebab case in styles.
Choosing between two classes
The object adds or removes a class. To switch between two classes, use a ternary inside an array:
<div :class="[inStock ? 'enStock' : 'enRupture']"></div>The array also takes a mix of strings and objects:
<div :class="['color-circle', { selectionne: index === selectedVariant }]"></div>Where to put the CSS
A single-file component can carry its own styles, isolated by the scoped attribute:
<style scoped>
.color-circle {
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
}
</style>These classes can be animated too: that is the subject of the chapter on transitions.
With scoped, those rules only apply to the elements of that component: Vue adds a unique attribute to the tags and repeats it in the selector. That is what stops a .button class defined in one component from repainting another.
Nothing changes in the template. The style object would be declared in data(), or better in computed if it depends on something else.
selectionnee class to the active colour swatch, with a thicker border. You will need the index of the loop and the selected variant.Common errors
backgroundColor, or 'background-color' in quotes.class and the conditional ones in :class.{ en-erreur: vrai } is invalid JavaScript: it has to be { 'en-erreur': vrai }.