Skip to content

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:

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

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

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

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

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

javascript
const activeClass = ref('active')
const errorClass = ref('text-danger')
vue
<div :class="[activeClass, errorClass]"></div>

This will render:

html
<div class="active text-danger"></div>

To conditionally apply a class, you can use a ternary expression:

vue
<div :class="[isActive ? activeClass : '', errorClass]"></div>

For better readability with multiple conditional classes, you can combine array and object syntax:

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

vue
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

Although camelCase keys are recommended, :style also supports kebab-cased CSS property names:

vue
<div :style="{ 'font-size': fontSize + 'px' }"></div>

The :style directive can co-exist with the plain style attribute:

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

html
<div style="color: red; font-size: 30px;"></div>

You can also bind directly to a style object, just like classes:

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

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

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

vue
<!-- 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:

vue
<!-- 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:

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

vue
<!-- Parent -->
<MyComponent :title="pageTitle" :likes="42" />
vue
<!-- 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:

vue
<!-- 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:

vue
<MyComponent v-bind="post" />

This is equivalent to:

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

vue
<!-- pass down parent props in common with a child component -->
<MyComponent v-bind="$props" />

$props vs $attrs

  • $props contains all declared props of the current component.
  • $attrs contains all attributes not declared as props on the current component.
vue
<!-- ChildComponent.vue -->
<script setup>
defineProps({
  title: String,
  abc: String
})
</script>
vue
<!-- 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.

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

vue
<input :value.prop="message" />

The .prop modifier also has a dedicated shorthand, .. The above example can be rewritten as:

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

vue
<input :value.attr="message" />

This is rarely needed, but can be useful when you want precise control over attribute behavior rather than property updates.