Vue.js List Rendering
List rendering lets you display every item in an array or object without writing a separate HTML element for each one. Vue's v-for directive loops through a collection and generates the HTML automatically.
The v-for Directive
v-for repeats an HTML element for each item in an array. You define a temporary variable name for the current item and provide the array to loop through.
<div id="app">
<ul>
<li v-for="fruit in fruits" :key="fruit">
{{ fruit }}
</li>
</ul>
</div>
<script>
Vue.createApp({
data() {
return {
fruits: ["Apple", "Banana", "Mango", "Orange"]
};
}
}).mount("#app");
</script>
Output:
• Apple • Banana • Mango • Orange
Diagram: How v-for Expands
Template (written once):
<li v-for="fruit in fruits">{{ fruit }}</li>
fruits array: ["Apple", "Banana", "Mango", "Orange"]
Vue generates:
<li>Apple</li>
<li>Banana</li>
<li>Mango</li>
<li>Orange</li>
The :key Attribute — Why It Matters
Vue needs a unique :key on every element in a v-for loop. This key helps Vue track which item is which when the list changes. Without it, Vue might update the wrong element when items are added, removed, or reordered.
Think of the key like a name tag at a conference. Without name tags, if someone leaves and a new person arrives in the same seat, you might confuse the two people. Name tags prevent that confusion.
<!-- Always provide :key -->
<li v-for="fruit in fruits" :key="fruit">{{ fruit }}</li>
<!-- For arrays of objects, use the unique ID -->
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
The key should be unique for each item. For simple arrays of strings, the string itself works. For arrays of objects, use a unique ID field.
Accessing the Index
v-for gives you a second optional variable — the current item's position (index) in the array, starting at 0.
<ol>
<li v-for="(fruit, index) in fruits" :key="fruit">
{{ index + 1 }}. {{ fruit }}
</li>
</ol>
Output:
1. Apple 2. Banana 3. Mango 4. Orange
Looping Through an Array of Objects
Most real data comes as an array of objects. You access each object's properties using dot notation inside the loop.
<div id="app">
<div v-for="student in students" :key="student.id">
<h4>{{ student.name }}</h4>
<p>Grade: {{ student.grade }} | Score: {{ student.score }}</p>
</div>
</div>
<script>
Vue.createApp({
data() {
return {
students: [
{ id: 1, name: "Alice", grade: "A", score: 95 },
{ id: 2, name: "Bob", grade: "B", score: 82 },
{ id: 3, name: "Charlie", grade: "C", score: 71 }
]
};
}
}).mount("#app");
</script>
Diagram: Object Array Rendering
students[0] → { id: 1, name: "Alice", grade: "A", score: 95 }
students[1] → { id: 2, name: "Bob", grade: "B", score: 82 }
students[2] → { id: 3, name: "Charlie", grade: "C", score: 71 }
Renders:
┌────────────────────────────┐
│ Alice │
│ Grade: A | Score: 95 │
├────────────────────────────┤
│ Bob │
│ Grade: B | Score: 82 │
├────────────────────────────┤
│ Charlie │
│ Grade: C | Score: 71 │
└────────────────────────────┘
Looping Through an Object's Properties
v-for also works on plain JavaScript objects. It loops through each key-value pair.
data() {
return {
profile: {
name: "Jordan Lee",
city: "Austin",
role: "Developer"
}
};
}
<ul>
<li v-for="(value, key) in profile" :key="key">
{{ key }}: {{ value }}
</li>
</ul>
Output:
• name: Jordan Lee • city: Austin • role: Developer
Looping a Fixed Number of Times
You can pass a number to v-for to repeat an element a set number of times.
<span v-for="n in 5" :key="n">★</span>
Output:
★ ★ ★ ★ ★
This is useful for star ratings, pagination dots, or any fixed repeating element.
Combining v-for with v-if
Do not put v-if and v-for on the same element — Vue processes v-if first, so it may not have access to the loop variable. Instead, wrap the element in a <template v-for> and place v-if on the inner element.
<!-- WRONG: v-if and v-for on the same element -->
<li v-for="item in items" v-if="item.inStock" :key="item.id">
{{ item.name }}
</li>
<!-- CORRECT: use template wrapper -->
<template v-for="item in items" :key="item.id">
<li v-if="item.inStock">{{ item.name }}</li>
</template>
Diagram: Filtered List with Template
items = [
{ id: 1, name: "Chair", inStock: true },
{ id: 2, name: "Table", inStock: false },
{ id: 3, name: "Lamp", inStock: true }
]
Loop processes all 3 items.
v-if filters:
Chair → inStock: true → shown
Table → inStock: false → hidden
Lamp → inStock: true → shown
Result:
• Chair
• Lamp
Reactive List Updates
Vue detects changes to arrays and updates the displayed list automatically. The following array methods trigger an update:
push()— adds an item to the endpop()— removes the last itemshift()— removes the first itemunshift()— adds an item to the beginningsplice()— adds or removes items at a positionsort()— reorders itemsreverse()— reverses the order
<div id="app">
<ul>
<li v-for="task in tasks" :key="task">{{ task }}</li>
</ul>
<button @click="addTask">Add Task</button>
</div>
<script>
Vue.createApp({
data() {
return { tasks: ["Design mockup", "Write tests"] };
},
methods: {
addTask() {
this.tasks.push("Deploy update");
}
}
}).mount("#app");
</script>
Diagram: Push Triggers Reactive Update
Before click:
tasks = ["Design mockup", "Write tests"]
Page shows: • Design mockup • Write tests
User clicks "Add Task"
→ tasks.push("Deploy update")
Vue detects the change:
tasks = ["Design mockup", "Write tests", "Deploy update"]
Page shows: • Design mockup • Write tests • Deploy update
(no page reload — Vue updates only the list)
Summary
The v-for directive repeats HTML elements for each item in an array or object. Always include a unique :key to help Vue track items efficiently. Use the (item, index) syntax to access the loop position. For arrays of objects, access properties with dot notation. Use a <template> wrapper when combining v-for and v-if. Mutating methods like push() trigger Vue's reactivity automatically, keeping the list in sync with your data.
