The x-for directive in AlpineJS is your go-to tool for dynamically rendering lists and repeating blocks of HTML. It allows you to loop through arrays or a specific range of numbers present in your component's data. This is conceptually similar to template loops you might be familiar with from Python web frameworks like Django ({% for item in items %}...{% endfor %}) or Flask (using Jinja2's {% for item in items %}...{% endfor %}).
x-for makes it easy to display collections of data, such as a list of products, user comments, navigation items, or any repeating UI element based on a data source.
Basic Iteration: <template x-for="item in items" :key="item.id"> ... </template>
This is the most common form. It iterates over an array called items (which must exist in your Alpine component's data scope). For each element in items, the content within the <template> tag is rendered. Inside the loop, item refers to the current element being processed.
<ul x-data="{ colors: [{id: 1, name: 'Red'}, {id: 2, name: 'Green'}, {id: 3, name: 'Blue'}] }">
<template x-for="color in colors" :key="color.id">
<li x-text="color.name"></li>
</template>
</ul>
Iteration with Index: <template x-for="(item, index) in items" :key="index"> ... </template>
If you need the current index of the iteration (0-based), you can specify a second variable (e.g., index). This is useful for display purposes or if your items don't have unique IDs and you're sure the list order won't change or items won't be removed from the middle (see "Gotchas" about :key).
<div x-data="{ fruits: ['Apple', 'Banana', 'Cherry'] }">
<template x-for="(fruit, index) in fruits" :key="index">
<p><span x-text="index + 1"></span>. <span x-text="fruit"></span></p>
</template>
</div>
Iterating a Number of Times: <template x-for="i in 5"> ... </template> (Implicit :key is i)
You can also loop a fixed number of times. Here, i will take values from 1 up to the specified number (inclusive). AlpineJS automatically uses i as the key in this scenario.
<div x-data>
<template x-for="i in 3">
<p>Iteration #<span x-text="i"></span></p>
</template>
</div>
The `template` Tag: x-for must always be placed on a <template> tag. This tag itself is not rendered in the DOM; its *content* is what gets repeated for each item in the loop.
Using :key for Performance and Stability: The :key attribute is crucial when using x-for with dynamic lists (lists that can change: items added, removed, or reordered). AlpineJS uses the key to identify and track individual DOM elements.
item.id if your data objects have unique IDs).index as a key, but be cautious. Using non-unique keys or inappropriate keys can lead to rendering errors or performance degradation.Forgetting :key or using a non-unique key: This is a frequent source of bugs. AlpineJS relies on :key to efficiently update, reorder, and manage elements in a list. If you omit it, or if the key you provide isn't unique for each item in the current list (e.g., using the loop index index when items can be reordered or removed from the middle), Alpine might get confused. This can result in incorrect DOM updates, visual glitches, loss of component state within list items, or performance issues. Always try to use a unique ID from your data item as the key (e.g., :key="product.id").
x-for must be on a <template> tag: Unlike some directives, x-for (and x-if) specifically require a <template> tag. The <template> element acts as an invisible wrapper whose content is used as the blueprint for each iteration. Trying to put x-for on a <div> or <li> directly will not work as intended.
<!-- CORRECT -->
<template x-for="item in items" :key="item.id">
<div x-text="item.name"></div>
</template>
<!-- INCORRECT -->
<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: In a loop like x-for="item in items", the item variable is a copy (or a reference to an object, but reassigning item itself won't change the array). If you try to change item directly (e.g., item.name = 'New Name' might change the displayed name for that iteration if item is an object, but reassigning item = someNewValue will not affect the original items array in your x-data). To modify the data, you must operate on the source array (items) itself, typically within a method called via an event listener (e.g., @click="updateItem(item.id)").
This list is populated by calling simulateFetchData() when the component initializes. Products are rendered using x-for with a unique product.id as the key.
Loading products...
No products found.
Price: $
Category: (Stock: )
Iterating over a simple array of strings and displaying their index. Here, :key="index" is used because the items are primitive and the list is static for this example part.
Using x-for="i in loopCount" to repeat a block. loopCount is a data property.