Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Lists: the each block

To render an array on the page — a list of tasks, posts, products — Svelte uses the {#each} block. It repeats a piece of markup for every element of the array.

The each block

<!-- src/routes/+page.svelte -->
<script>
  let todos = $state([
    { id: 1, text: 'Buy bread', done: false },
    { id: 2, text: 'Call Oleg', done: true },
    { id: 3, text: 'Write the report', done: false }
  ]);
</script>
 
<ul>
  {#each todos as todo}
    <li>{todo.text}</li>
  {/each}
</ul>

The page shows a list of three items. todos as todo means "for every element of the todos array, call it todo".

Index

A second name after a comma gives the element's position, starting from zero:

<!-- src/routes/+page.svelte: markup only, the script stays the same -->
<ul>
  {#each todos as todo, i}
    <li>{i + 1}. {todo.text}</li>
  {/each}
</ul>

The items get the numbers "1.", "2.", "3.". The markup stays in the same src/routes/+page.svelte file, the <script> block does not change.

Key

If elements are added, removed or reordered, Svelte must know which item belongs to which object. For this you give a key in parentheses — a unique value of the element, usually id:

<!-- src/routes/+page.svelte: markup only, the script stays the same -->
<ul>
  {#each todos as todo (todo.id)}
    <li>
      <input type="checkbox" checked={todo.done} />
      {todo.text}
    </li>
  {/each}
</ul>

With a key, when a task is deleted Svelte removes exactly its element and leaves the rest untouched — together with checkmarks, focus and animations. Always give a key when the list can change.

Empty list

The branch is rendered when the array is empty:

<script>
  let todos = $state([]);
</script>
 
<ul>
  {#each todos as todo (todo.id)}
    <li>{todo.text}</li>
  {:else}
    <li>No tasks yet</li>
  {/each}
</ul>

While the array is empty, the list shows the item "No tasks yet".

Destructuring

The element's properties can be unpacked into variables right away:

<!-- src/routes/+page.svelte: markup only, the script stays the same -->
{#each todos as { id, text, done } (id)}
  <li>{text} {done ? '(done)' : ''}</li>
{/each}

This is convenient when the object is big and you need two or three fields.

Common mistake

Using the index as the key: {#each todos as todo, i (i)}. When the first task is deleted, all the others shift, their indexes change, and Svelte thinks the elements themselves changed. Checkbox marks and typed text "jump" to neighbouring rows. Use the element's permanent id as the key.

Thanks for reading!

Donate to the site — we work hard for you.