Description: The x-for directive in AlpineJS allows you to create dynamic lists and repeating blocks of HTML by looping through arrays or a range of numbers in your component data. This is conceptually similar to how you might use {% for item in items %} ... {% endfor %} in Python web frameworks like Django or Flask to render templates.
Iterating over an array:
<template x-for="item in items" :key="item.id">
<div x-text="item.name"></div>
</template>
Here, items is an array in your Alpine component's data. For each item in items, the content inside the <template> tag is duplicated. item.id is used as a unique :key for each rendered element, which is crucial for performance and stability.
Accessing the index:
<template x-for="(item, index) in items" :key="index">
<div>
<span x-text="index + 1"></span>:
<span x-text="item.name"></span>
</div>
</template>
You can also access the current index of the iteration. While using index as a :key is possible, it's generally recommended to use a unique ID from the data itself if items can be reordered, added, or removed, as the index can change.
Iterating a specific number of times:
<template x-for="i in 5" :key="i">
<div>Iteration <span x-text="i"></span></div>
</template>
This will repeat the content inside the <template> tag 5 times. The variable i will take values from 1 to 5 (inclusive).
Using :key for performance and stability:
The :key attribute is essential when using x-for. AlpineJS uses the key to identify each DOM element created by the loop. This allows Alpine to efficiently update, reorder, or remove elements when the underlying data array changes. Without a proper key, or with non-unique keys, you might encounter:
item.id) as the key. If your items don't have unique IDs and won't be reordered or have items removed from the middle, the index can be a fallback, but it's less robust.
Forgetting :key or using a non-unique key:
As mentioned, AlpineJS relies on :key to efficiently manage list rendering. If you forget :key, Alpine will warn you in the console. If you use a non-unique key (like the loop index when the list can be reordered, or items added/removed from arbitrary positions), Alpine might get confused about which DOM element corresponds to which data item. This can lead to strange visual bugs, data not updating correctly, or input fields losing focus/state.
Best Practice: Always use a unique ID from your data objects (e.g., product.id, user.uuid) for the :key.
x-for must be on a <template> tag:
Similar to the x-if directive, x-for must be placed on a <template> HTML tag. The <template> tag itself is not rendered in the DOM; its content is used as the blueprint for each item in the loop. AlpineJS clones this content for each iteration.
<!-- CORRECT -->
<template x-for="item in items" :key="item.id">
<div x-text="item.name"></div>
</template>
<!-- INCORRECT - This will not work as intended -->
<div x-for="item in items" :key="item.id" x-text="item.name"></div>
Trying to modify the iteration variable (item) directly to update the original array:
When you loop like x-for="item in items", the item variable within each iteration is essentially a copy or a read-only reference for that specific iteration's data. If you try to change properties of item (e.g., item.name = 'New Name') directly within an event handler inside the loop, this will not automatically update the original items array in your Alpine component's data.
To modify the data, you must operate on the source array (this.items in your component's methods). For example, find the item in this.items by its ID and then modify it, or replace an item, or push/splice the array.
// In your Alpine component:
{
items: [{id: 1, name: 'Old Name'}],
updateItemName(itemId, newName) {
const itemToUpdate = this.items.find(i => i.id === itemId);
if (itemToUpdate) {
itemToUpdate.name = newName; // This modifies the original array
}
}
}
New items are added with a temporary ID starting with 'new_'.
| ID | Name | Detail | Actions |
|---|---|---|---|
The above 5 blocks are generated using x-for="i in 5".