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 template loops like {% for item in items %} in Python web frameworks like Django or Flask.
The x-for directive is powerful and flexible. Here are its main forms and concepts:
Iterating over an array of items:
<template x-for="item in items" :key="item.id">
<div>
<span x-text="item.name"></span>
</div>
</template>
In this syntax:
items is an array in your Alpine component's data.item is a variable that holds the current element during each iteration. You can access its properties (e.g., item.name).:key="item.id" is crucial. The key must be a unique string or number for each item in the list. It helps Alpine efficiently track, update, and reorder elements. If your items have a unique ID property (like item.id), that's the best choice for the key.Iterating with an index:
<template x-for="(item, index) in items" :key="index">
<div>
<span x-text="index"></span>: <span x-text="item.name"></span>
</div>
</template>
You can also get the index (0-based) of the current item.
index as a :key, it's generally only safe if the list order is stable and items are not inserted/deleted from the middle. If the list can change dynamically, a unique ID from the item itself is more robust.Iterating a fixed number of times:
<template x-for="i in 5" :key="i">
<div>Iteration <span x-text="i"></span></div>
</template>
This will repeat the template's content 5 times. The variable i will take values from 1 to 5 (inclusive).
Using :key effectively:
Alpine uses the :key attribute to identify and track each element generated by x-for. This is vital for performance and stability, especially when the list of items can change (additions, deletions, reordering).
Forgetting :key or using a non-unique key:
This is the most common issue. AlpineJS relies heavily on :key to efficiently update and reorder DOM elements in a list.
Forgetting it, or using a key that isn't unique for each item (like the loop index if items can be reordered or removed from the middle), can lead to:
:key. If your data items have unique IDs (e.g., from a database), use those (:key="item.id").
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.
<!-- Correct -->
<template x-for="item in items" :key="item.id">
<div x-text="item.name"></div>
</template>
<!-- Incorrect: x-for directly on a div -->
<!-- <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:
The item (or whatever you name it) in x-for="item in items" is a local, read-only copy for that specific iteration. Modifying item (e.g., item.name = 'new name') inside the loop will not change the original items array in your x-data.
This is similar to how loop variables work in many languages; they are scoped to the loop. To update the data, you need to modify the source array itself (e.g., by calling a method in your Alpine component that updates this.items).
// Inside an Alpine component method:
updateItemName(itemId, newName) {
const itemIndex = this.items.findIndex(i => i.id === itemId);
if (itemIndex > -1) {
// Correct: Modify the original array or its objects
this.items[itemIndex].name = newName;
// Or, for full reactivity if replacing item:
// this.items[itemIndex] = { ...this.items[itemIndex], name: newName };
// this.items = [...this.items]; // If re-assigning the whole array
}
}
These links are generated by iterating over an array populated by simulateFetchData(). Each item uses its unique id as the :key.
Add or remove tasks. The :key is essential here for Alpine to correctly update the list without losing focus or state.
No tasks yet. Add one above!
This demonstrates x-for="i in N" to repeat a block of HTML a specific number of times. Here, i goes from 1 to 3.