Basic Svelte
Introduction
Bindings
Classes and styles
Advanced Svelte
Advanced reactivity
Motion
Advanced bindings
Advanced transitions
Context API
Special elements
<script module>
Next steps
Basic SvelteKit
Introduction
Routing
Loading data
Headers and cookies
Shared modules
API routes
$app/state
Errors and redirects
Advanced SvelteKit
Page options
Link options
Advanced routing
Advanced loading
Environment variables
Conclusion
In the previous chapter, we used deferred transitions to create the illusion of motion as elements move from one todo list to the other.
To complete the illusion, we also need to apply motion to the elements that aren’t transitioning. For this, we use the animate directive.
First, import the flip function — flip stands for ‘First, Last, Invert, Play’ — from svelte/animate into TodoList.svelte:
<script>
import { flip } from 'svelte/animate';
import { send, receive } from './transition.js';
let { todos, remove } = $props();
</script><script lang="ts">
import { flip } from 'svelte/animate';
import { send, receive } from './transition.js';
let { todos, remove } = $props();
</script>Then add it to the <li> elements:
<li
class={{ done: todo.done }}
in:receive={{ key: todo.id }}
out:send={{ key: todo.id }}
animate:flip
>The movement is a little slow in this case, so we can add a duration parameter:
<li
class={{ done: todo.done }}
in:receive={{ key: todo.id }}
out:send={{ key: todo.id }}
animate:flip={{ duration: 200 }}
>
durationcan also be ad => millisecondsfunction, wheredis the number of pixels the element has to travel
Note that all the transitions and animations are being applied with CSS, rather than JavaScript, meaning they won’t block (or be blocked by) the main thread.
<script>
import TodoList from './TodoList.svelte';
const todos = $state([
{ id: 1, done: false, description: 'write some docs' }, { id: 2, done: false, description: 'start writing blog post' }, { id: 3, done: true, description: 'buy some milk' }, { id: 4, done: false, description: 'mow the lawn' }, { id: 5, done: false, description: 'feed the turtle' }, { id: 6, done: false, description: 'fix some bugs' }]);
let uid = todos.length + 1;
function remove(todo) {const index = todos.indexOf(todo);
todos.splice(index, 1);
}
</script>
<div class="board">
<input
placeholder="what needs to be done?"
onkeydown={(e) => {if (e.key !== 'Enter') return;
todos.push({id: uid++,
done: false,
description: e.currentTarget.value
});
e.currentTarget.value = '';
}}
/>
<div class="todo">
<h2>todo</h2>
<TodoList todos={todos.filter((t) => !t.done)} {remove} /></div>
<div class="done">
<h2>done</h2>
<TodoList todos={todos.filter((t) => t.done)} {remove} /></div>
</div>
<style>
.board {display: grid;
grid-template-columns: 1fr 1fr;
grid-column-gap: 1em;
max-width: 36em;
margin: 0 auto;
}
.board > input {font-size: 1.4em;
grid-column: 1/3;
padding: 0.5em;
margin: 0 0 1rem 0;
}
h2 {font-size: 2em;
font-weight: 200;
}
</style>