Vue.js Attribute Binding

Double curly braces {{ }} place data into the text of an element. But HTML attributes — like href, src, class, and disabled — live inside the opening tag, not in the content area. Vue's attribute binding connects your data to these attributes using the v-bind directive.

Why {{ }} Does Not Work in Attributes

This code does not work:

<!-- WRONG: Curly braces inside an attribute -->
<a href="{{ url }}">Visit Page</a>

<!-- Vue will not process this. The browser literally shows: -->
<a href="{{ url }}">Visit Page</a>

For attributes, you must use v-bind:

<!-- CORRECT -->
<a v-bind:href="url">Visit Page</a>

Diagram: Text Interpolation vs Attribute Binding

Element structure:
<tagname attribute="value"> content </tagname>
           │                  │
           │                  └── Use {{ }} here
           └── Use v-bind: here

Example:
<a v-bind:href="url">{{ linkText }}</a>
         │               │
         │               └── {{ }} fills in the text
         └── v-bind: fills in the attribute value

Basic v-bind Usage

<div id="app">
  <a v-bind:href="websiteUrl">Go to Website</a>
  <img v-bind:src="imageUrl" v-bind:alt="imageCaption">
</div>

<script>
  Vue.createApp({
    data() {
      return {
        websiteUrl: "https://example.com",
        imageUrl: "https://example.com/photo.jpg",
        imageCaption: "A sample photo"
      };
    }
  }).mount("#app");
</script>

Vue replaces the attribute values with the actual data from data(). When the data changes, the attribute updates instantly.

The Shorthand — Using Colon Only

Writing v-bind: for every attribute is repetitive. Vue provides a shorthand: just use a colon : instead of v-bind:.

<!-- Full syntax -->
<a v-bind:href="url">Link</a>

<!-- Shorthand (same result) -->
<a :href="url">Link</a>

Most Vue developers use the colon shorthand. Both work the same way.

Binding the class Attribute

The class attribute is special in Vue because you can bind it dynamically using an object or an array.

Object Syntax — Turn Classes On and Off

Use an object where each key is a class name and the value is a true/false condition. Vue adds the class when the value is true and removes it when false.

<div id="app">
  <p :class="{ active: isActive, error: hasError }">
    Status message
  </p>
  <button @click="isActive = !isActive">Toggle Active</button>
</div>

<script>
  Vue.createApp({
    data() {
      return {
        isActive: false,
        hasError: true
      };
    }
  }).mount("#app");
</script>

Diagram: Class Object Binding

:class="{ active: isActive, error: hasError }"

isActive = false, hasError = true
  →  class="error"            (active removed, error added)

isActive = true,  hasError = true
  →  class="active error"     (both added)

isActive = true,  hasError = false
  →  class="active"           (error removed)

isActive = false, hasError = false
  →  class=""                 (no classes)

Array Syntax — Always Apply Multiple Classes

Use an array to apply a fixed list of classes from data properties.

data() {
  return {
    baseClass: "card",
    themeClass: "dark-theme"
  };
}

<div :class="[baseClass, themeClass]">Content</div>
<!-- Renders as: <div class="card dark-theme"> -->

Mixing Static and Dynamic Classes

You can combine a fixed class attribute with a dynamic :class binding on the same element. Vue merges them.

<div class="box" :class="{ highlight: isHighlighted }">
  Content
</div>

<!-- When isHighlighted = true: -->
<div class="box highlight">Content</div>

<!-- When isHighlighted = false: -->
<div class="box">Content</div>

Binding the style Attribute

You can bind inline styles using an object. The object keys are CSS property names (in camelCase) and the values come from your data.

<div id="app">
  <p :style="{ color: textColor, fontSize: textSize + 'px' }">
    Styled Text
  </p>
</div>

<script>
  Vue.createApp({
    data() {
      return {
        textColor: "blue",
        textSize: 20
      };
    }
  }).mount("#app");
</script>

Diagram: Style Binding Mapping

data:
  textColor = "blue"
  textSize  = 20

Template:
:style="{ color: textColor, fontSize: textSize + 'px' }"

Rendered attribute:
style="color: blue; font-size: 20px;"

Binding Boolean Attributes

Some HTML attributes are boolean — they either exist on the element or they don't. Examples: disabled, checked, readonly. Vue handles these correctly when you bind them.

<div id="app">
  <button :disabled="isButtonDisabled">Submit</button>
</div>

<script>
  Vue.createApp({
    data() {
      return { isButtonDisabled: true };
    }
  }).mount("#app");
</script>

Diagram: Boolean Attribute Behavior

isButtonDisabled = true
  →  <button disabled>Submit</button>   (button is grayed out)

isButtonDisabled = false
  →  <button>Submit</button>            (disabled attribute removed)

Vue removes the attribute entirely when the value is false, null, or undefined. It adds it when the value is truthy.

Binding Multiple Attributes at Once

You can bind an entire object of attributes to an element using v-bind without specifying an argument.

data() {
  return {
    linkAttrs: {
      href: "https://example.com",
      target: "_blank",
      title: "Open in new tab"
    }
  };
}

<a v-bind="linkAttrs">External Link</a>

<!-- Renders as: -->
<a href="https://example.com" target="_blank" title="Open in new tab">
  External Link
</a>

Dynamic Attribute Names

In Vue 3, you can also make the attribute name itself dynamic by wrapping it in square brackets.

data() {
  return {
    attrName: "title",
    attrValue: "This is a tooltip"
  };
}

<p :[attrName]="attrValue">Hover over me</p>
<!-- Renders as: -->
<p title="This is a tooltip">Hover over me</p>

Practical Example: Product Card

Here is a real-world example combining multiple types of attribute binding:

<div id="app">
  <div class="product-card" :class="{ 'out-of-stock': !inStock }">
    <img :src="imageUrl" :alt="productName">
    <h3>{{ productName }}</h3>
    <p :style="{ color: inStock ? 'green' : 'red' }">
      {{ inStock ? 'Available' : 'Out of Stock' }}
    </p>
    <button :disabled="!inStock">Add to Cart</button>
  </div>
</div>

<script>
  Vue.createApp({
    data() {
      return {
        productName: "Wireless Mouse",
        imageUrl: "mouse.jpg",
        inStock: false
      };
    }
  }).mount("#app");
</script>

Diagram: Product Card Output When Out of Stock

inStock = false

┌──────────────────────────────────────────┐
│  class="product-card out-of-stock"       │
│  ┌───────────────────────────┐           │
│  │ [image of Wireless Mouse] │           │
│  └───────────────────────────┘           │
│  Wireless Mouse                          │
│  Out of Stock  (red color)               │
│  [Add to Cart]  ← button is disabled     │
└──────────────────────────────────────────┘

Summary

Attribute binding uses v-bind: (or the shorthand :) to connect data to HTML attributes. You bind href, src, alt, and other standard attributes directly to data values. The class binding accepts objects (for toggling) and arrays (for combining). The style binding accepts a CSS property object. Boolean attributes like disabled appear or disappear automatically based on the truthy or falsy value of the bound data.

Leave a Comment

Your email address will not be published. Required fields are marked *