Render arrays and objects dynamically in the DOM.
1Iterating over Arrays
We can use the v-for directive to render a list of items based on an array. The directive requires a special syntax in the form of item in items, where items is the source data array.
2The Importance of Keys
When Vue is updating a list of elements rendered with v-for, by default it uses an 'in-place patch' strategy. If the order of the data items has changed, Vue will patch each element in-place. To give Vue a hint so it can track each node's identity, you must provide a unique :key attribute.
3Iterating over Objects
You can also use v-for to iterate through the properties of an object. The syntax is (value, key, index) in myObject.
4Step-by-Step Breakdown
Web apps are mostly just lists of data: Tweets, Products, Emails. To render lists in Vue, we use the v-for directive.
The syntax for v-for is item in items, where items is your source data array, and item is an alias for the array element being iterated on.
What directive do you use to render a list of items from an array in Vue?
- →v-map
- →v-for
- →v-repeat
You can also extract the index of the current item by using parentheses: (item, index) in items.
CRITICAL RULE: When using v-for, you MUST provide a unique key attribute for each item. This helps Vue track changes and optimize rendering.
What attribute is MANDATORY to include when rendering lists with v-for so Vue can track node identity?
- →id
- →key
- →index
You should NEVER use the array index as the key if the list can be reordered or have items deleted. Always use a unique ID from your database.
v-for can also iterate over the properties of an Object, not just Arrays!
When iterating over an Object using v-for="(value, key) in object", which argument represents the property name (like "author")?
- →value
- →key
With v-if and v-for, you now have the power to render dynamic, data-driven interfaces. Let's keep building!
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Keying Ensures Accessible State Survives Reordering
When a v-for list uses a stable :key (an item's database id), Vue preserves and moves the actual DOM node during reordering instead of destroying and recreating it — so focus position, an expanded/collapsed ARIA state, or an in-progress form input inside a list item survives a re-sort or filter, instead of resetting and disorienting keyboard and screen-reader users.
<li v-for="task in tasks" :key="task.id">
<input v-model="task.note" />
</li>SEO Implications
- 1
v-for Renders Every Item Into Real DOM Nodes, Fully Crawlable
There's no virtualization or lazy rendering built into v-for itself — every element in the source array becomes an actual DOM node (and, during SSR, actual HTML), so a v-for list of 200 blog post links is exactly as indexable as 200 manually written <a> tags. Virtual-scrolling libraries that only render visible rows are a separate opt-in with their own SSR considerations.
Best Practices
Never Use the Array Index as :key If the List Can Reorder
Using :key="index" defeats the purpose of keying whenever items can be added, removed, filtered, or sorted, because the index-to-item mapping shifts even though the key values look unchanged to Vue — leading to state like a checked checkbox sticking to the wrong row. Use a stable identifier from the data itself.
Frequent Bugs
Combining v-if and v-for on the exact same element.
In Vue 3, v-if has higher precedence than v-for on the same node, so the v-if condition cannot access the v-for scope variable and Vue raises a compile-time error. Move the filtering into a computed property, or wrap the loop in a <template v-for="..."> with the v-if on the element inside it.
Real-World Examples
Rendering a Paginated Comment Thread
A comments component renders v-for="comment in visibleComments" :key="comment.id", where visibleComments is a computed property slicing the full comments array by the current page number, keeping the v-for simple while all pagination math lives in one computed.
const visibleComments = computed(() =>
comments.value.slice(page.value * 20, (page.value + 1) * 20)
);