Vue Directives

Directives are special v- prefixed attributes that let you attach reactive behavior directly to elements in a Vue template.

What Is a Directive?

A directive is a special attribute, always prefixed with v-, that you place on an element in a template. Directives tell Vue to do something reactive to that element or its children — toggle it, repeat it, bind an attribute on it, or listen for events on it — whenever the expression you give it changes. Directives are compiled away at build time, so there is no runtime cost beyond the reactive binding itself.

The Built-In Directive Set

Vue ships with a small set of core directives that cover almost every templating need: conditional rendering, list rendering, attribute and event binding, two-way form binding, and raw HTML insertion.

  • v-bind (:) — binds an attribute or prop to an expression
  • v-on (@) — attaches an event listener
  • v-if / v-else-if / v-else — conditionally renders elements
  • v-show — toggles CSS display without removing the element
  • v-for — renders a list of elements from an array or object
  • v-model — creates two-way binding on form inputs
  • v-html — renders raw HTML instead of escaped text
  • v-once / v-pre — renders once and skips re-compilation, respectively

Directive Syntax and Arguments

The general shape is v-directive:argument.modifier="value". The argument (after the colon) usually names the attribute or event, and modifiers (after a dot) tweak behavior, such as .prevent to call event.preventDefault() automatically. The two most common directives, v-bind and v-on, have dedicated shorthand symbols that you will see in almost every real Vue codebase.

DirectiveShorthandExample
v-bind::href="url"
v-on@@click="save"
v-model(none)v-model="name"

Combining v-bind, v-if, and v-on

const app = Vue.createApp({
  data() {
    return {
      isLoggedIn: true,
      avatarUrl: 'https://example.com/avatar.png'
    }
  },
  methods: {
    logOut() {
      this.isLoggedIn = false
    }
  }
})

app.mount('#app')

<!-- template -->
<div id="app">
  <img v-bind:src="avatarUrl" alt="User avatar" />
  <p v-if="isLoggedIn">Welcome back!</p>
  <p v-else>Please sign in.</p>
  <button v-on:click="logOut">Log out</button>
</div>
Note: Real-world Vue code almost always uses the shorthand symbols — : and @ — instead of writing v-bind: and v-on: in full. This course uses both forms so you can recognize either style.

v-for with a required :key

const app = Vue.createApp({
  data() {
    return {
      tasks: [
        { id: 1, label: 'Write lesson' },
        { id: 2, label: 'Record video' },
        { id: 3, label: 'Publish exercise' }
      ]
    }
  }
})

app.mount('#app')

<!-- template -->
<ul id="app">
  <li v-for="task in tasks" :key="task.id">
    {{ task.label }}
  </li>
</ul>
Note: Always give v-for a unique :key. Without it, Vue may reuse and mutate the wrong DOM elements when the list changes order, which can leave stale text or form values on screen.

v-model paired with v-on

const app = Vue.createApp({
  data() {
    return {
      search: ''
    }
  },
  methods: {
    runSearch() {
      alert(`Searching for: ${this.search}`)
    }
  }
})

app.mount('#app')

<!-- template -->
<div id="app">
  <input v-model="search" placeholder="Search..." />
  <button @click="runSearch">Go</button>
  <p>You typed: {{ search }}</p>
</div>
Note: v-model is really shorthand for binding :value and listening for an @input event at the same time. Later lessons cover v-bind and v-if in depth; v-model gets its own dedicated lesson later in this course.

Exercise: Vue Directives

What is a Vue directive?