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>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>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>Exercise: Vue v-if
What happens to an element when its v-if condition becomes false?