Vue.js: Class & Style Binding
Last updated: 2026-10-20
:class and :style are Vue's two most-used bindings — they let you switch CSS class names and inline styles dynamically based on data. They are really two special forms of v-bind; because they are used so often, they were wrapped up as "syntactic sugar".
Five forms cover 95% of cases: object syntax, array syntax, ternaries, computed properties, and string concatenation.
1. What You'll Learn
:classobject syntax: toggle one or several classes by condition:classarray syntax: apply several classes at once- Mixing arrays + objects: complex class combinations
:styleobject syntax: dynamic inline styles:stylearray syntax: merging multiple style objects- CSS variable binding (recommended in Vue 3)
2. A Style Problem with Order Status Badges
(1) The Pain: 5 Statuses, 5 if Checks
Alice needs to show 5 order statuses in different colors in the admin:
<!-- ❌ The broken version: five v-if branches adding classes -->
<span v-if="status === 'pending'" class="badge yellow">Pending</span>
<span v-else-if="status === 'paid'" class="badge green">Paid</span>
<span v-else-if="status === 'shipped'" class="badge blue">Shipped</span>
<span v-else-if="status === 'delivered'" class="badge gray">Delivered</span>
<span v-else class="badge red">Cancelled</span>
Product manager Charlie:
"Alice, this is ugly. What happens when we add 3 more statuses next month? You can't keep copy-pasting. We need a clean dynamic approach."
(2) The Vue :class Solution: 1 Line for 5 Statuses
(3) The Payoff
- Less HTML: 5 lines of if-else → 1 line of :class
- Maintainable: adding a status only changes the computed, not the template
- Readable: the status-to-class mapping lives in one place, so the logic is clear
3. :class: 5 Syntax Forms
(1) String Syntax
(2) Object Syntax (Most Common)
(3) Array Syntax
(4) Coexisting with a Static class
(5) class on Components
▶ Example: 5 :class Syntax Forms
▶ Try it YourselfOutput:
Five lines, each a different class combination: badge, active, active error, active (the disabled class is absent because canEdit is true), and active from the computed object.
1. String → class="badge"
2. Object → class="active"
3. Array → class="active error"
4. Array + object → class="active"
5. Computed property → class="active"
4. :style: 5 Syntax Forms
(1) Object Syntax
(2) CSS Property Name Conversion
Vue converts JS naming to CSS naming automatically:
(3) Array Syntax (Merging Objects)
(4) Automatic Prefixing
Vue 3 adds browser prefixes to CSS properties automatically (decided by the browser engine):
// You write:
{ transform: 'rotate(45deg)' }
// Vue adds:
{
-webkit-transform: 'rotate(45deg)',
transform: 'rotate(45deg)'
}
(5) CSS Variables (Recommended in Vue 3)
▶ Example: 5 :style Syntax Forms
▶ Try it YourselfOutput:
Five stacked rows. Row 1 is red 16px text; row 2 has a green background and 20px padding;
row 3 merges to white text on a green background; row 4 exposes --theme-color: #35495e;
row 5 renders white text on a dark blue background with 20px padding.
1. Basic object red, 16px
2. Multiple properties #42b883 background, 20px padding
3. Array merge white text, #42b883 background
4. CSS variable --theme-color: #35495e
5. Computed property white text on #35495e, 20px padding
5. Complete Example: Dynamic Order Status
▶ Example: Order Status Badge (5-State Toggle)
▶ Try it YourselfOutput:
A yellow Pending badge appears by default.
Clicking each button swaps both the label and the background color: Paid green, Shipped blue, Delivered gray, Cancelled red.
[ Pending ] ← yellow background
[ Paid ] ← green background
[ Shipped ] ← blue background
[ Delivered ] ← gray background
[ Cancelled ] ← red background
(1) 📊 5 Common Mistakes
| Mistake | Symptom | Fix |
|---|---|---|
| String class does not react | Hard-coded class never switches | Bind it with :class |
| Misspelled array classes | Duplicate classes override each other | Use object syntax |
| Missing style units | The number 16 is not treated as 16px | Write the string '16px' |
| Wrong CSS property name | font-size needs to be fontSize |
Use camelCase or quotes |
| :class conflicts | Static + dynamic share a name | Vue merges them, so it is fine |
(2) 📊 5 Performance Comparisons
| Form | Compiled output | Performance | Good for |
|---|---|---|---|
| String | Direct string concatenation | ⭐⭐⭐⭐⭐ | Simple |
| Object | Static analysis | ⭐⭐⭐⭐ | Medium |
| Array | String concatenation | ⭐⭐⭐⭐ | Multiple classes |
| Array + object | Mixed processing | ⭐⭐⭐ | Complex |
| Computed property | Cached value | ⭐⭐⭐⭐⭐ | Complex logic |
(3) 📊 class vs style, 5 Key Differences
| Dimension | class | style |
|---|---|---|
| Recommendation | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| CSS reuse | Easy (reuse class names) | Hard (styles scatter) |
| Performance | Higher (browser optimizations) | Slightly lower |
| Priority | Depends on the selector | Inline (highest) |
| Theme switching | Easy (swap classes) | Easy (swap CSS variables) |
❓ FAQ
class="x" plus a dynamic :class="{active: y}" merges automatically (the final class is "x active" or "x").<div style="color: red"> is native HTML, and <div :style="'color: red'"> also works. But an object like :style="{ color: 'red' }" can bind variables dynamically. Objects are recommended.{'--my-var': value} in :style and use var(--my-var) in CSS. Vue 3 recommends CSS variables for theming because they are more efficient than binding styles directly — only one variable changes and the DOM does not reflow.class attribute automatically (Vue 3 default). For multi-root components, bind $attrs.class to a specific element explicitly.<div v-if="show" :class="{ active: isActive }">, the element is not rendered at all when show is false, so isActive has no effect either.:style="{ '--primary': theme.primary }" and use color: var(--primary) everywhere. Switching themes changes a single variable instead of 100 classes.📖 Summary
:classand:styleare v-bind syntactic sugar, simplified because they are used so much- :class has 5 forms: string, object, array, array + object, and computed property
- :style has 5 forms: object, array, array + object, CSS variables, and computed property
- Static class and dynamic :class merge automatically
- Vue 3 adds CSS browser prefixes automatically
- CSS variables are Vue 3's recommended theming approach (more efficient than swapping styles)
- Performance: object/computed > array > string
📝 Exercises
-
Basic (⭐) Use :class object syntax to implement 3 button states:
- primary: blue background, white text
- success: green background, white text
- danger: red background, white text
Data:
const variant = ref('primary') -
Intermediate (⭐⭐) Build an order list where each row shows a colored badge based on the order status:
- 5 statuses (pending/paid/shipped/delivered/cancelled)
- Use a computed property to return the class object
- Use :style to set the icon color for each status
-
Challenge (⭐⭐⭐) Build a complete theme-switching system:
- 3 themes (light/dark/high-contrast)
- Bind the theme colors with CSS variables (primary/secondary/background/text)
- Switch the theme class name with :class
- Remember the user's choice in localStorage
- Switch themes without reloading the page (reactive updates)