Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Transitions and animations

A transition is an animation that plays when an element appears on the page or disappears from it. In Svelte the built-in transitions are added with one directive, without CSS keyframes or separate libraries.

The transition directive

Built-in transitions live in the svelte/transition module. The simplest is fade, a smooth appearance and disappearance:

<!-- src/routes/+page.svelte -->
<script>
  import { fade } from 'svelte/transition';
 
  let showHint = $state(true);
</script>
 
<button onclick={() => (showHint = !showHint)}>Hint</button>
 
{#if showHint}
  <p transition:fade>Mark finished tasks with a checkmark.</p>
{/if}

The button hides and shows the paragraph, and each time it smoothly fades out or in. A transition plays when an element is added or removed by an {#if} or {#each} block.

Parameters

A transition can take a settings object:

<script>
  import { fly } from 'svelte/transition';
 
  let showHint = $state(true);
</script>
 
{#if showHint}
  <p transition:fly={{ y: -20, duration: 300 }}>A new hint</p>
{/if}

The paragraph flies in from 20 pixels above over 300 milliseconds. The double curly braces are an object inside an expression.

TransitionWhat it does
fadechanges opacity
flymoves and changes opacity
slideexpands vertically
scalegrows or shrinks

Different transitions in and out

The in: and out: directives set transitions separately for appearing and disappearing:

<!-- src/routes/+page.svelte: a row of the to-do list -->
<script>
  import { fly, fade } from 'svelte/transition';
 
  let todos = $state([{ id: 1, text: 'Buy bread' }]);
</script>
 
<ul>
  {#each todos as todo (todo.id)}
    <li in:fly={{ x: -30 }} out:fade>{todo.text}</li>
  {/each}
</ul>

A new task slides in from the left, and a deleted one quietly fades away.

Reorder animation

When list items change order, the flip function from the svelte/animate module moves them smoothly to their new places. It works only in a keyed {#each} block:

<script>
  import { flip } from 'svelte/animate';
 
  let todos = $state([
    { id: 1, text: 'Buy bread' },
    { id: 2, text: 'Call Oleg' }
  ]);
</script>
 
<button onclick={() => todos.reverse()}>Reverse</button>
<ul>
  {#each todos as todo (todo.id)}
    <li animate:flip={{ duration: 300 }}>{todo.text}</li>
  {/each}
</ul>

After the click the rows do not jump but smoothly swap places.

Common mistake

Putting transition: on an element that is always on the page and expecting an animation when its text changes. A transition plays only when an element is added or removed. For it to run, wrap the element in {#if} or {#each}.

Thanks for reading!

Donate to the site — we work hard for you.