Chapter 6 of 11

VueJS 3 tutorial – Binding CSS classes and inline styles

verified on 2 September 2026 · 4 min

Quick answer

: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.

By the end of this chapter, you will know how to reflect the state of the application in its appearance, without touching the DOM.

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:

src/App.vue
<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:

src/App.vue
<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:

html
<div :style="{ backgroundColor: variant.color }"></div>

Writing background-color without quotes would be read as a subtraction. Kebab case is still available, inside quotes:

html
<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:

src/App.vue
<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:

html
<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:

src/App.vue
<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:

src/App.vue
<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.

html
<!-- é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:

html
<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:

html
<div :class="[inStock ? 'enStock' : 'enRupture']"></div>

The array also takes a mix of strings and objects:

html
<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:

src/App.vue
<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.

In the Options API

Nothing changes in the template. The style object would be declared in data(), or better in computed if it depends on something else.

ExerciseAdd a 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

background-color without quotes In the object passed to :style, the hyphen is read as a subtraction. Write backgroundColor, or 'background-color' in quotes.
Assuming :class overwrites class The two attributes are merged. Keep the fixed classes in class and the conditional ones in :class.
A hyphenated class name without quotes { en-erreur: vrai } is invalid JavaScript: it has to be { 'en-erreur': vrai }.
Newsletter

New tests, tutorials and projects, by e-mail.

Reproducible tests, versioned code, dated results. Never any spam.