Conditional rendering: v-if and v-show
Conditional rendering means showing an element only when a condition holds. In the task list it is a "No tasks" message for an empty list, or a cheer when everything is done.
The v-if directive
<!-- src/App.vue -->
<script setup>
import { ref } from 'vue'
const todos = ref([])
</script>
<template>
<h1>My tasks</h1>
<p v-if="todos.length === 0">No tasks yet.</p>
</template>"No tasks yet." appears under the heading. As soon as the array has at least one task, the paragraph disappears from the page — Vue removes it from the DOM.
v-else and v-else-if
Alternative branches go right after the element with v-if:
<script setup>
import { ref, computed } from 'vue'
const todos = ref([
{ id: 1, text: 'Buy bread', done: true },
{ id: 2, text: 'Call Anna', done: false },
])
const remaining = computed(() => todos.value.filter((t) => !t.done).length)
</script>
<template>
<p v-if="todos.length === 0">No tasks yet.</p>
<p v-else-if="remaining === 0">All done!</p>
<p v-else>Tasks left: {{ remaining }}</p>
</template>Right now the page shows "Tasks left: 1". Vue checks the conditions top to bottom and renders only the first matching branch.
A group of elements
To show several elements on a condition without an extra wrapper, use the template tag — it does not end up on the page itself:
<template>
<template v-if="todos.length > 0">
<h2>List</h2>
<p>Click a task to mark it.</p>
</template>
</template>The heading and the paragraph appear together when the list is not empty.
The v-show directive
v-show also hides an element, but differently: the element always stays in the DOM, and Vue only toggles its display: none style.
<script setup>
import { ref } from 'vue'
const showHelp = ref(false)
</script>
<template>
<button @click="showHelp = !showHelp">Help</button>
<p v-show="showHelp">Type the task and press Enter.</p>
</template>The button opens and closes the hint. Developer tools show that the paragraph is always on the page; only its style changes.
Which to choose
v-if | v-show | |
|---|---|---|
| Hidden element | Removed from the DOM | Stays, display: none |
| Initial render | Cheaper if the condition is false | Always rendered |
| Frequent toggling | More expensive | Cheaper |
Works with v-else and template | Yes | No |
If an element is toggled often — a menu, a hint, tabs — use v-show. If the condition rarely changes or the element is heavy — v-if.
Common mistake
There must be no other elements between v-if and v-else:
<template>
<p v-if="todos.length === 0">No tasks yet.</p>
<hr>
<p v-else>Task list</p>
</template>Vue cannot find a partner for v-else and reports a compile error. Put the branches strictly one after another.