Vue.js: Conditional & List Rendering

Last updated: 2026-10-20

Conditional rendering (v-if / v-show) and list rendering (v-for) are the two most frequently used directives in Vue templates. The first controls "whether to show it", the second controls "how many to show". Combined, they can render 90% of UI scenarios.

Mastering the 5 key differences between v-if and v-for, along with the correct usage of :key, is what lets you write high-performance Vue applications.

Related Directives:v-else-if v-show v-else v-for v-if

1. What You'll Learn


2. The "Nested if" Code Disaster in a Dashboard

(1) Pain Point: 5 Nested v-ifs, a Debugging Nightmare

Alice's dashboard code has spiraled out of control:

Charlie's code review comment:

"Alice, this is simply unreadable. Five levels of nested v-if. What happens when we add 2 more conditions? We need a clearer pattern."

(2) The Vue Solution: Flatten the v-ifs + Computed Properties

(3) Benefits


3. v-if / v-else-if / v-else Conditional Rendering

(1) Basic Syntax

(2) The template Element

(3) 5 Usage Scenarios

Scenario Use v-if
Logged in / not logged in ✅
Loading / load complete ✅
Empty data / has data ✅
Error state ✅
Toggling visibility frequently ❌ (use v-show)

▶ Example: 5 Ways to Write v-if/v-show

▶ Try it Yourself

Output:

TEXT
Six pieces of content plus two toggle buttons.
The first two lines are visible because show is true; 3.
Type A shows because type starts as 'A'; the admin block renders <h1>4.
Admin Panel</h1> with an Edit button;
5a is hidden (its v-if is false) while 5b is visible.
Clicking Toggle show removes line 1 from the DOM and sets display: none on line 2;
clicking Toggle type swaps between 3. Type A and 3. Type B.
TEXT
1. v-if visible (click to toggle)
2. v-show visible
3. Type A
4. Admin Panel
[Edit]
5b. Frequent toggle (v-show)
[Toggle show] [Toggle type]

4. The 5 Key Differences Between v-show and v-if

(1) Core Difference

(2) 5 Comparisons

Dimension v-if v-show
DOM operation Removes the element when the condition is false Always in the DOM, only toggles display
Toggle performance Poor (destroy/rebuild each time) Good (only swaps CSS)
Initial render Nothing rendered when the condition is false Always rendered (even when invisible)
With transition ✅ Perfect (enter/leave animation) ❌ Not supported
Best for Occasional toggling Frequent toggling

(3) How to Choose

JS
// Occasional toggling (logged in / logged out) → v-if
<div v-if="isLoggedIn">Welcome, {{ user.name }}</div>
<div v-else>Please login</div>

// Frequent toggling (tab switching) → v-show
<button v-show="isActive">Active</button>
<button v-show="!isActive">Inactive</button>

5. List Rendering with v-for

(1) Iterating Arrays

(2) Iterating Objects

(3) Iterating Numbers

(4) Iterating Strings

▶ Example: 5 Ways to Write v-for

▶ Try it Yourself

Output:

TEXT
Five sections rendered in order — a plain array list (Apple / Banana / Cherry), the same list with 1.–3.
prefixes, the object rendered as name: Alice / age: 25 / email: alice@example.com, the numbers [1][2][3][4][5], and one span per character of Hello.
TEXT
1. Array
Apple
Banana
Cherry

2. Array + index
1. Apple
2. Banana
3. Cherry

3. Object
name: Alice
age: 25
email: alice@example.com

4. Number
[1][2][3][4][5]

5. String
H e l l o

▶ Example: v-if and v-for Priority

▶ Try it Yourself

Output:

TEXT
The list starts with a single row, Alice, plus the button Toggle Alice status.
Clicking it flips isActive on the user with id === 1, so the row disappears;
clicking again brings Alice back.
Bob never appears because the computed property filters him out before v-for runs.
TEXT
Alice
[Toggle Alice status]
⚠️ In Vue 3, v-if has a higher priority than v-for (the reverse of Vue 2). The official recommendation: do not use them together — separate them with a template or filter with a computed property.


6. What :key Does and Best Practices

(1) What Is :key?

:key gives every v-for item a unique identity, which helps Vue update the DOM efficiently.

(2) Why Do We Need :key?

100%
graph LR
    A[Original list A B C] --> B[New list B C D]
    B --> C[No key: nodes may get mismatched]
    B --> D[With key: correct updates]
    
    style C fill:#ff6b6b
    style D fill:#42b883

Without :key:

With :key:

(3) :key Best Practices

VUE
<!-- ✅ Recommended: unique ID -->
<li v-for="user in users" :key="user.id">

<!-- ✅ Second choice: a unique field (email, phone number, etc.) -->
<li v-for="user in users" :key="user.email">

<!-- ❌ Avoid: index (items get mismatched when data changes) -->
<li v-for="(user, index) in users" :key="index">

<!-- ❌ Never: random() (different on every render, forces a rebuild) -->
<li v-for="user in users" :key="Math.random()">

▶ Example: Comparing 5 Ways to Use :key

▶ Try it Yourself

Output:

TEXT
Five lists that look identical on the first render — Alice / Bob twice, Post A / Post B, then X / Y twice.
The difference only shows up on updates: keys 1–3 stay bound to the right data, index can shift content when the list is reordered, and Math.random() produces a new key on every render, so Vue tears down and rebuilds every node.
TEXT
1. Unique ID (best)
Alice
Bob

2. Unique field
Alice
Bob

3. Composite key
Post A
Post B

4. Using index (second choice)
X
Y

5. ❌ random() (never)
X
Y

7. List Filtering / Sorting / Pagination

(1) Filtering + Sorting (Computed Properties)

JS
const { ref, computed } = Vue

const items = ref([
  { id: 1, name: 'iPhone', price: 999, category: 'phone' },
  { id: 2, name: 'MacBook', price: 2499, category: 'laptop' },
  { id: 3, name: 'iPad', price: 599, category: 'tablet' }
])

const searchQuery = ref('')
const selectedCategory = ref('all')
const sortBy = ref('price')  // 'price' / 'name'

// Filtering + sorting (computed caches automatically)
const filteredItems = computed(() => {
  let result = items.value
  
  // 1. Filter by search term
  if (searchQuery.value) {
    result = result.filter(item =>
      item.name.toLowerCase().includes(searchQuery.value.toLowerCase())
    )
  }
  
  // 2. Filter by category
  if (selectedCategory.value !== 'all') {
    result = result.filter(item => item.category === selectedCategory.value)
  }
  
  // 3. Sort
  result = [...result].sort((a, b) => {
    if (sortBy.value === 'price') return a.price - b.price
    if (sortBy.value === 'name') return a.name.localeCompare(b.name)
    return 0
  })
  
  return result
})

(2) Pagination

JS
const currentPage = ref(1)
const pageSize = ref(10)

// Data for the current page
const paginatedItems = computed(() => {
  const start = (currentPage.value - 1) * pageSize.value
  return filteredItems.value.slice(start, start + pageSize.value)
})

// Total number of pages
const totalPages = computed(() =>
  Math.ceil(filteredItems.value.length / pageSize.value)
)

8. Complete Example: Dynamic Product List

▶ Example: Complete Filtering + Sorting + Pagination Example

▶ Expand runnable example (67 lines)
▶ Try it Yourself

Output:

TEXT
A search box, two selects, three rows sorted by price ascending (iPad - $599, iPhone - $999, MacBook - $2499), and a pager reading 1 / 1 with both buttons disabled.
Typing i narrows the list, choosing phone keeps only iPhone, and switching the sort to Name reorders the rows alphabetically — all without touching the original items array.
TEXT
[Search...] [All v] [Price v]

iPad - $599
iPhone - $999
MacBook - $2499

[Previous] 1 / 1 [Next]

(1) 📊 5 Common Mistakes

Mistake Symptom Fix
No :key Items get mismatched, poor performance Add :key="item.id"
Using v-for and v-if together Confusing v-if priority Wrap with template or use computed
Using index as the key Items get mismatched when sorting Use a unique ID
v-show does not support <transition> No animation Switch to v-if + <transition>
The list is too large (100k+) Page freezes Use vue-virtual-scroller for virtual scrolling

Related Directives:v-else-if v-show v-else v-for v-if

❓ FAQ

Q How do I choose between v-if and v-show?
A For occasional toggling use v-if (it saves the initial render); for frequent toggling use v-show (it avoids repeatedly destroying/rebuilding the DOM). Logged in / logged out → v-if; tab switching → v-show.
Q Must v-for use :key?
A It is strongly recommended, to avoid performance problems and mismatched component state. A unique ID (item.id) is best, index is second, and random() should never be used.
Q If v-if and v-for are used together, which wins?
A In Vue 3, v-if has a higher priority than v-for (the reverse of Vue 2). But the official recommendation is not to use them together — separate them with a template or filter with a computed property.
Q What is the template element for?
A template is Vue's logical wrapper element; it is not rendered to the DOM. Use it when v-if/v-for must cover multiple elements, so you avoid extra divs.
Q What should I do when list performance is poor?
A 3 optimizations: (1) add :key; (2) use computed to cache the filtering/sorting results; (3) for large lists (100k+) use vue-virtual-scroller so only the visible area is rendered.
Q Can v-for over an object give me the key/value?
A Yes. v-for="(value, key, index) in obj" — the parameter order is value, key, index.
Q How do I show a hint when there is no data?
A Combine v-if/v-else: <div v-if="items.length">list</div><div v-else>No data</div>.
Q How do I highlight the clicked item in a list?
A Track an activeIndex and compare it per item: @click="activeIndex = item.id" :class="{ active: activeIndex === item.id }".

📖 Summary


📝 Exercises

  1. Basic (difficulty ⭐) Implement a logged-in / logged-out switch with v-if/v-else:

    • Logged in: show the username and a "Logout" button
    • Logged out: show "Please log in" and the login form
    • Wrap multiple elements with template
  2. Intermediate (difficulty ⭐⭐) Build a Todo list with v-for:

    • 3 states: All / Active / Completed (switched by 3 buttons)
    • The list shows tasks matching the current state
    • Each item has "Complete" and "Delete" buttons
    • The footer shows "Active: N items"
  3. Challenge (difficulty ⭐⭐⭐) Build a complete product filter + sort + pagination system (5 files):

    1. Product data: 30 items with name/price/category/createdAt
    2. Search: fuzzy match on name
    3. Category filter: 5 categories (all/phone/laptop/tablet/headphone)
    4. Sorting: price ascending/descending/name/newest
    5. Pagination: 10 items per page with page-number navigation
    6. Performance: cache the filter/sort results with computed
    7. Large-list optimization: test with 1000 items and make sure it stays smooth
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏