Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

x-for and keys

The x-for directive repeats a piece of markup for each item of an array. This is how lists are rendered: tasks, products, comments. When the array changes, Alpine adds and removes elements on the page by itself.

A simple list

Like x-if, x-for goes on a <template>. The value is written as item in array:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<ul x-data="{ tasks: ['Buy milk', 'Call Oleg', 'Pay for internet'] }">
  <template x-for="task in tasks">
    <li x-text="task"></li>
  </template>
</ul>

The page shows a list of three items. The task variable takes each value of the array in turn and is visible inside the <template>.

The index

To get an item's position, list two variables in parentheses:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<ul x-data="{ tasks: ['Buy milk', 'Call Oleg'] }">
  <template x-for="(task, index) in tasks">
    <li x-text="(index + 1) + '. ' + task"></li>
  </template>
</ul>

The items are numbered: "1. Buy milk", "2. Call Oleg".

Keys

If list items can be removed or reordered, each one needs a key — a unique value by which Alpine recognizes the item. The key is set with the :key attribute on the <template>. Usually it is the object's id:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<ul x-data="{
  tasks: [
    { id: 1, title: 'Buy milk' },
    { id: 2, title: 'Call Oleg' },
    { id: 3, title: 'Pay for internet' }
  ],
  remove(id) {
    this.tasks = this.tasks.filter(task => task.id !== id);
  }
}">
  <template x-for="task in tasks" :key="task.id">
    <li>
      <span x-text="task.title"></span>
      <button @click="remove(task.id)">Delete</button>
    </li>
  </template>
</ul>

The "Delete" button removes its own task: remove() keeps every task except the chosen one, and Alpine removes the matching item. :key is short for x-bind:key; x-bind is the next lesson.

A range of numbers

Instead of an array you can give a number — the variable then runs from 1 up to it:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
 
<div x-data>
  <template x-for="page in 5">
    <button x-text="page"></button>
  </template>
</div>

Five buttons numbered 1 to 5 appear — a starting point for pagination.

Common mistake

Using the index as the key: :key="index". After the first task is removed, the second one gets index 0, and Alpine treats it as the item that was deleted. Element state — typed text, a checked box — can end up on the wrong row. Use a stable id as the key, and keep one root element inside the <template>.

Thanks for reading!

Donate to the site — we work hard for you.