Conditional and List Rendering

Chapter 4
Conditional and List Rendering — v-if, v-for
Showing, hiding, and repeating elements — Vue's directive answer to JSX conditionals and .map()

React handles conditionals and lists with plain JavaScript in JSX (ternaries, &&, .map()); Angular uses @if/@for blocks. Vue uses directives on the element itself — v-if and v-for — closer to Angular's older *ngIf/*ngFor style, but with their own conveniences.

v-if / v-else-if / v-else

<p v-if="status === 'loading'">Loading...</p> <p v-else-if="status === 'error'">Something went wrong.</p> <p v-else>Ready!</p>

v-if conditionally renders an element based on a truthy expression, with optional v-else-if and v-else chained on adjacent elements. Like Angular's @if (and unlike a CSS display: none), a false v-if genuinely removes the element from the DOM entirely. The full v-if/v-else-if/v-else chain neatly handles the loading/error/success pattern that ran through the React projects, without a lookup object or chained ternaries.

v-show — Toggle Visibility, Keep It in the DOM

<div v-show="isExpanded">Details here...</div>

v-show looks similar but works differently: the element stays in the DOM and is toggled with CSS display. Use v-if when the element is rarely shown or expensive to create (it's truly added/removed); use v-show when toggling frequently (e.g. a dropdown), since flipping a CSS property is cheaper than repeatedly creating and destroying the element. This explicit choice is something React and Angular handle more implicitly — Vue names it directly.

v-for — Rendering a List

<ul> <li v-for="fruit in fruits" :key="fruit">{{ fruit }}</li> </ul>

v-for="item in items" repeats the element once per array entry — Vue's .map() equivalent. The :key binding is required (using v-bind from Chapter 3) and serves the identical purpose as React's key and Angular's track: a stable, unique identifier so Vue can update the DOM efficiently when the list changes. A real object array keys on its id:

<li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>

v-for with an Index

<li v-for="(todo, index) in todos" :key="todo.id"> {{ index + 1 }}. {{ todo.text }} </li>

A second variable in parentheses gives the current index — (todo, index) in todos — useful for numbering. Note the index is the position, not a good :key on its own (same caution as React's array index): prefer a stable id for the key whenever one exists.

Don't use v-if and v-for on the same element
Putting both directives on one element is discouraged and has ambiguous precedence. To filter a list, either filter the array first (in a computed property, Chapter 5) or wrap the v-for in a <template v-if>. A common clean pattern is a computed visibleTodos that returns only the items to show, then v-for over that — exactly the "filter before mapping" approach from React's Fundamentals Chapter 6.

The <template> Wrapper

<template v-for="item in items" :key="item.id"> <dt>{{ item.term }}</dt> <dd>{{ item.definition }}</dd> </template>

To repeat or conditionally render multiple elements without adding a wrapper element to the DOM, put the directive on a <template> tag — an invisible grouping element that renders only its contents. This is Vue's equivalent of React's fragment (<>...</>), used here specifically to attach a directive to a group.

VueAngularReact
v-if / v-else-if / v-else@if / @else if / @elseTernary / &&
v-show[hidden] / [style.display]Conditional class/style
v-for + :key@for + track.map() + key
<template> wrapper<ng-container>Fragment <>...</>

Coding Challenges

Challenge 1

Build a component with a status ref ("loading"/"error"/"success") cycled by a button, using v-if/v-else-if/v-else to show different content for each status.

📄 View solution
Challenge 2

Given an array of objects ({ id, name }) in a ref, render them as a list with v-for and :key, plus a numbered version using the (item, index) form showing "1. Name", "2. Name", etc.

📄 View solution
Challenge 3

Build a component with a list of items and a "Show details" toggle button. Use v-show to reveal a details panel (kept in the DOM), and separately use v-if elsewhere to show a "No items" message when the array is empty.

📄 View solution

Chapter 4 Quick Reference

  • v-if / v-else-if / v-else — conditional rendering; truly adds/removes the element from the DOM
  • v-show — toggles CSS display, keeping the element in the DOM (cheaper for frequent toggles)
  • v-for="item in items" — list rendering; a required :key (= React's key / Angular's track)
  • (item, index) in items — also exposes the index; don't use the index as the key if a stable id exists
  • Don't combine v-if and v-for on one element — filter via a computed property instead
  • <template> with a directive — group multiple elements without an extra DOM node (= React fragment)
  • Next chapter: computed properties and watchers