Logic blocks: if, each, key

Svelte · Essentials · 11 min

Conditionals and lists appear on nearly every screen, and keys decide whether list items keep their state.

Svelte markup uses blocks for logic. They open with #, continue with : and close with /.

Conditionals:

{#if user}
  <p>Hi {user.name}</p>
{:else if loading}
  <p>Loading...</p>
{:else}
  <button>Log in</button>
{/if}

Lists with {#each}:

  • {#each items as item} or {#each items as item, i} for the index.
  • Destructure directly: {#each users as { id, name }}.
  • An {:else} branch renders when the list is empty.
  • Add a key in parentheses: {#each todos as todo (todo.id)}. With a key, Svelte moves, inserts and removes DOM nodes to match items; without one it updates nodes in place by position, so state like input focus or a child component's internal state can end up on the wrong row after insertions or deletions. Keys are also required for animate: directives.

{#each} accepts arrays, array-like objects and other iterables such as Sets (they are converted with Array.from).

`{#key value}` destroys and recreates its content whenever value changes. Use it to restart a transition or reset a child component's state when, say, the selected id changes.

{@html markup} renders raw HTML; only use it with trusted, sanitised content.

Example

<script>
  let todos = $state([
    { id: 1, text: 'Buy milk', done: false },
    { id: 2, text: 'Learn Svelte', done: true },
  ]);
  let selected = $state(1);
</script>

{#each todos as todo, i (todo.id)}
  <label class:done={todo.done}>
    {i + 1}. <input type="checkbox" bind:checked={todo.done} /> {todo.text}
  </label>
{:else}
  <p>Nothing to do!</p>
{/each}

{#if todos.every((t) => t.done)}
  <p>All done</p>
{:else}
  <p>{todos.filter((t) => !t.done).length} left</p>
{/if}

{#key selected}
  <p>Details for #{selected}</p>   <!-- recreated when selected changes -->
{/key}

Remember

  • {#if}...{:else if}...{:else}...{/if} for conditionals
  • {#each list as item, i (item.id)} with a stable key; {:else} for empty lists
  • {#key x} recreates its content whenever x changes

Watch out for

  • Leaving out the key in lists whose items are reordered or removed, so per-row state sticks to the wrong item.

Check yourself

  1. What does the `(todo.id)` part of `{#each todos as todo (todo.id)}` do?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: svelte.dev/docs/svelte/each