v-bind
You've already seen how to use the v-bind directive to bind HTML attributes to reactive data. Vue provides special enhancements when v-bind is used with class and style attributes. In addition to strings, these bindings can evaluate to objects or arrays.
Binding HTML Classes
Objects
You can pass an object to :class (short for v-bind:class) to dynamically toggle classes:
<div :class="{ active: isActive, 'text-danger': hasError }"></div>The above syntax means the presence of active and text-danger classes will be determined by the truthiness of the isActive and hasError properties respectively.
The :class directive can co-exist with the plain class attribute:
<script setup>
import { ref } from 'vue'
const isActive = ref(true)
const hasError = ref(false)
</script>
<template>
<div
class="static"
:class="{ active: isActive, 'text-danger': hasError }"
></div>
</template>The above code will render this:
<div class="static active"></div>The class list will automatically update when isActive or hasError changes.
The bound object doesn't need to be defined inline:
<script setup>
import { reactive } from 'vue'
const classObject = reactive({
active: true,
'text-danger': false
})
</script>
<template>
<div :class="classObject"></div>
</template>You can also bind to a computed property that returns an object. This is a common and powerful pattern:
<script setup>
import { ref, computed } from 'vue'
const isActive = ref(true)
const hasError = ref(false)
const classObject = computed(() => ({
active: isActive.value && !hasError.value,
'text-danger': hasError.value
}))
</script>
<template>
<div :class="classObject"></div>
</template>Arrays
You can bind :class to an array to apply a list of classes:
const activeClass = ref('active')
const errorClass = ref('text-danger')<div :class="[activeClass, errorClass]"></div>This will render:
<div class="active text-danger"></div>To conditionally apply a class, you can use a ternary expression:
<div :class="[isActive ? activeClass : '', errorClass]"></div>For better readability with multiple conditional classes, you can combine array and object syntax:
<div :class="[{ [activeClass]: isActive }, errorClass]"></div>Binding Inline Styles
Objects
Similar to classes, you can pass an object to :style (short for v-bind:style) to dynamically apply styles:
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>Although camelCase keys are recommended, :style also supports kebab-cased CSS property names:
<div :style="{ 'font-size': fontSize + 'px' }"></div>The :style directive can co-exist with the plain style attribute:
<script setup>
import { ref } from 'vue'
const fontSize = ref(30)
</script>
<template>
<div
style="color: red"
:style="{ 'font-size': fontSize + 'px' }"
></div>
</template>The above code will render:
<div style="color: red; font-size: 30px;"></div>You can also bind directly to a style object, just like classes:
<script setup>
import { reactive } from 'vue'
const styleObject = reactive({
color: 'red',
fontSize: '30px'
})
</script>
<template>
<div :style="styleObject"></div>
</template>Arrays
Just like :class, you can bind :style to an array of style objects. These objects will be merged, with later entries taking precedence:
<div :style="[baseStyles, overridingStyles]"></div>Browser Compatibility
Auto-prefixing
When using CSS properties that require a vendor prefix in :style, Vue automatically adds the appropriate prefixes at runtime by checking browser support.
Multiple Values (Fallbacks)
You can provide an array of fallback (prefixed) values to a style property:
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>Only the last supported value will be applied. In modern browsers, this will typically result in display: flex.
With Components
Binding Classes
When you use the class attribute on a component with a single root element, those classes will be added to the component's root element and merged with any existing class already on it.
For example, if there is a component named MyComponent with a <p> tag as root element:
<!-- the component -->
<MyComponent class="baz boo" />
<!-- child component template -->
<p class="foo bar">Hi!</p>The above code will add foo bar baz boo classes to the <p> tag.
If your component has multiple root elements, you need to explicitly decide where the incoming classes should go. You can access them via the $attrs object:
<!-- the component -->
<MyComponent class="baz boo" />
<!-- MyComponent template using $attrs -->
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>This will render:
<p class="baz boo">Hi!</p>
<span>This is a child component</span>Binding Component Props
When using v-bind on components, attributes that match declared props will be passed as props instead of being treated as plain HTML attributes.
<!-- Parent -->
<MyComponent :title="pageTitle" :likes="42" /><!-- Child -->
<script setup>
defineProps({
title: String,
likes: Number
})
</script>
<template>
<h1>{{ title }}</h1>
<p>{{ likes }} likes</p>
</template>If a bound attribute does not match a declared prop, it will automatically fall through to the component’s root element as an attribute:
<!-- Parent -->
<MyComponent id="main-title" />
<!-- Child (rendered) -->
<h1 id="main-title">...</h1>You can also use v-bind without an argument to pass an entire object of props at once:
<MyComponent v-bind="post" />This is equivalent to:
<MyComponent
:title="post.title"
:author="post.author"
:content="post.content"
/>You can use $props to forward all props received by a parent component to a child component. This is useful when you want the child to automatically receive the same set of props without explicitly listing them:
<!-- pass down parent props in common with a child component -->
<MyComponent v-bind="$props" />$props vs $attrs
$propscontains all declared props of the current component.$attrscontains all attributes not declared as props on the current component.
<!-- ChildComponent.vue -->
<script setup>
defineProps({
title: String,
abc: String
})
</script><!-- ParentComponent.vue -->
<script setup>
defineProps({ title: String })
</script>
<template>
<!-- Forwards only declared props (title in this case) -->
<ChildComponent v-bind="$props" />
<!-- Forwards only undeclared attributes (abc in this case) -->
<ChildComponent v-bind="$attrs" />
</template>Modifiers
Vue provides modifiers for v-bind that change how attributes are applied:
.camel.prop.attr
NOTE
v-bind on a Vue component sets a prop, not a DOM property. Modifiers .camel, .prop and .attr only affect native DOM elements, not Vue component props.
.camel
The .camel modifier converts a kebab-cased attribute name into camelCase. This is mainly useful when binding SVG attributes or DOM properties that expect camelCase names.
<svg :view-box.camel="box"></svg>This ensures the bound attribute is treated as viewBox instead of view-box.
.prop
NOTE
.prop and .attr are available only in Vue 3.2 and above.
When using v-bind on a native DOM element, Vue by default checks whether the element has the key defined as a DOM property. If so, it sets the value as a DOM property instead of an HTML attribute. You can, however, explicitly force this behavior by using the .prop modifier:
<input :value.prop="message" />The .prop modifier also has a dedicated shorthand, .. The above example can be rewritten as:
<input .value="message" />.attr
If you instead want to explicitly force the binding to be treated as a plain HTML attribute, even if a corresponding DOM property exists, use .attr modifier:
<input :value.attr="message" />This is rarely needed, but can be useful when you want precise control over attribute behavior rather than property updates.
