Vue v-if

v-if, v-else-if, and v-else conditionally add or remove elements from the DOM based on the truthiness of an expression.

Conditional Rendering with v-if

v-if evaluates its expression, and if the result is falsy, the element — along with all of its children and any component instances inside it — is not rendered at all. It isn't merely hidden with CSS; it is actually absent from the DOM, and Vue will destroy and recreate it as the condition flips.

Chaining Branches: v-else-if and v-else

v-else-if and v-else must appear on the element immediately following a v-if or v-else-if, with no other markup in between. Vue evaluates the chain top to bottom and renders only the first branch whose condition is truthy, exactly like a JavaScript if/else if/else statement.

  • v-else-if and v-else must be direct siblings of the preceding v-if/v-else-if element
  • Wrap multiple elements in a <template v-if="..."> to group them without adding an extra wrapper div
  • Evaluation stops at the first truthy branch in the chain
  • Each branch mounts and unmounts its own elements, so lifecycle hooks fire on every switch

A three-way v-if chain

const app = Vue.createApp({
  data() {
    return {
      score: 82
    }
  }
})

app.mount('#app')

<!-- template -->
<div id="app">
  <p v-if="score >= 90">Grade: A</p>
  <p v-else-if="score >= 75">Grade: B</p>
  <p v-else-if="score >= 60">Grade: C</p>
  <p v-else>Grade: F</p>
</div>
Note: Use <template v-if="..."> when you need to conditionally show several elements together. The <template> tag itself never renders to the DOM, so you avoid adding an unnecessary wrapper element just to hold the directive.

Grouping Branches and Reusing Elements

When two branches use the same tag (for example, an <input> in both the if and the else), Vue's diffing algorithm will reuse that single DOM element for efficiency rather than destroying and recreating it — which means it can keep old values like a typed-in string. Give each branch its own :key to force Vue to treat them as genuinely different elements.

Forcing distinct elements with :key

const app = Vue.createApp({
  data() {
    return {
      loginType: 'username'
    }
  },
  methods: {
    swap() {
      this.loginType = this.loginType === 'username' ? 'email' : 'username'
    }
  }
})

app.mount('#app')

<!-- template -->
<div id="app">
  <template v-if="loginType === 'username'">
    <label>Username</label>
    <input :key="'username-input'" placeholder="Username" />
  </template>
  <template v-else>
    <label>Email</label>
    <input :key="'email-input'" placeholder="Email" />
  </template>
  <button @click="swap">Switch</button>
</div>
Note: Avoid placing v-if directly on the same element as v-for — the exact precedence rules are easy to misremember, and the mixed intent (loop this, but only sometimes) is a common source of bugs. Filter the list with a computed property instead, and keep v-for clean.

Filtering with a computed property instead of v-if + v-for

const app = Vue.createApp({
  data() {
    return {
      showActiveOnly: true,
      users: [
        { id: 1, name: 'Grace', active: true },
        { id: 2, name: 'Alan', active: false },
        { id: 3, name: 'Ada', active: true }
      ]
    }
  },
  computed: {
    visibleUsers() {
      return this.showActiveOnly
        ? this.users.filter(u => u.active)
        : this.users
    }
  }
})

app.mount('#app')

<!-- template: filter with a computed property, not v-if next to v-for -->
<ul id="app">
  <li v-for="user in visibleUsers" :key="user.id">
    {{ user.name }}
  </li>
</ul>
Note: The next lesson introduces v-show, an alternative to v-if that keeps the element in the DOM and simply toggles its visibility — often cheaper for elements that flip back and forth frequently.

Exercise: Vue v-if

What happens to an element when its v-if condition becomes false?