Vue v-bind

v-bind dynamically links an HTML attribute or component prop to a piece of Vue state, updating the attribute whenever that state changes.

Why You Need v-bind

A plain HTML attribute like src="logo.png" is a static string baked into the markup. v-bind replaces that static string with a JavaScript expression that Vue evaluates and re-evaluates reactively, so the attribute's value can change whenever your component's data changes — no manual DOM calls required.

The Shorthand Colon Syntax

v-bind:attribute="expression" can always be shortened to :attribute="expression". The shorthand is so common in real Vue codebases that most developers use it exclusively, reserving the full v-bind: spelling for teaching contexts or for the rare case where the colon shorthand would collide with another tool.

  • Binding a URL to src or href
  • Toggling classes with an object or array via :class
  • Applying inline styles with an object via :style
  • Binding boolean attributes like disabled or checked
  • Passing data down to a child component as a prop

Binding image and link attributes

const app = Vue.createApp({
  data() {
    return {
      logoUrl: '/images/logo.png',
      docsLink: 'https://vuejs.org'
    }
  }
})

app.mount('#app')

<!-- template -->
<div id="app">
  <img :src="logoUrl" :alt="'Company logo'" />
  <a :href="docsLink">Read the docs</a>
</div>
Note: Prefer the : shorthand everywhere. It reads cleanly once you're used to it, and it's what you'll see in virtually every Vue example, library, and job codebase.

Binding class and style

:class and :style get special treatment in Vue: instead of only accepting a string, they also accept an object (keys are class names or CSS properties, values are booleans or CSS values) or an array of values. This makes conditional styling far less error-prone than string concatenation.

SyntaxExampleResult
String:class="'active'"Always applies the active class
Object:class="{ active: isActive }"Applies active only while isActive is true
Array:class="[baseClass, extraClass]"Applies every class listed, in order

Toggling a class with object syntax

const app = Vue.createApp({
  data() {
    return {
      isActive: true,
      hasError: false
    }
  },
  methods: {
    toggleActive() {
      this.isActive = !this.isActive
    }
  }
})

app.mount('#app')

<!-- template -->
<div id="app">
  <p :class="{ active: isActive, error: hasError }">
    Status text
  </p>
  <button @click="toggleActive">Toggle</button>
</div>
Note: If the expression you bind evaluates to undefined — for example a typo'd data property — Vue will silently render nothing for that attribute rather than throwing. Double-check property names when a bound attribute seems to have no effect.

Spreading multiple attributes at once

const app = Vue.createApp({
  data() {
    return {
      isSaving: false,
      buttonAttrs: {
        id: 'save-btn',
        title: 'Save your changes'
      }
    }
  }
})

app.mount('#app')

<!-- template -->
<div id="app">
  <button v-bind="buttonAttrs" :disabled="isSaving">
    {{ isSaving ? 'Saving...' : 'Save' }}
  </button>
</div>
Note: v-bind is one-directional: data flows from your component into the DOM. For form inputs where you also need the DOM to write back into your data, you'll use v-model, covered in a later lesson.

Exercise: Vue v-bind

What is the shorthand for writing v-bind:href="url"?