Crossfade helps items smoothly change places or fade in and out in a list. It makes the list look nice and easy to follow.
Crossfade for list items in Svelte
import { crossfade } from 'svelte/transition'; const [send, receive] = crossfade({ duration: 400, fallback(node, params) { return { duration: 400, css: t => `opacity: ${t}` }; } }); <ul> {#each items as item (item.id)} <li in:receive={{ key: item.id }} out:send={{ key: item.id }}>{item.text}</li> {/each} </ul>
You import crossfade from svelte/transition.
It returns two functions: send and receive. Use them as out:send and in:receive on list items.
import { crossfade } from 'svelte/transition'; const [send, receive] = crossfade(); <ul> {#each items as item (item.id)} <li in:receive={{ key: item.id }} out:send={{ key: item.id }}>{item.text}</li> {/each} </ul>
const [send, receive] = crossfade({ duration: 600 });
const [send, receive] = crossfade({ fallback(node) { return { duration: 300, css: t => `transform: scale(${t}); opacity: ${t}` }; } });
This Svelte component shows a list of fruits. You can add new fruits or remove existing ones. When items are added or removed, they smoothly crossfade in or out. The list items are keyboard accessible and the buttons have ARIA labels for screen readers.
<script> import { crossfade } from 'svelte/transition'; import { cubicOut } from 'svelte/easing'; let items = [ { id: 1, text: 'Apple' }, { id: 2, text: 'Banana' }, { id: 3, text: 'Cherry' } ]; const [send, receive] = crossfade({ duration: 500, easing: cubicOut, fallback(node) { return { duration: 500, css: t => `opacity: ${t}` }; } }); function removeItem(id) { items = items.filter(item => item.id !== id); } function addItem() { const newId = items.length ? Math.max(...items.map(i => i.id)) + 1 : 1; items = [...items, { id: newId, text: `Fruit ${newId}` }]; } </script> <button on:click={addItem} aria-label="Add item">Add Item</button> <ul> {#each items as item (item.id)} <li in:receive={{ key: item.id }} out:send={{ key: item.id }} tabindex="0"> {item.text} <button on:click={() => removeItem(item.id)} aria-label="Remove {item.text}">Remove</button> </li> {/each} </ul> <style> ul { list-style: none; padding: 0; max-width: 300px; margin-top: 1rem; } li { background: #def; margin: 0.5rem 0; padding: 0.5rem 1rem; border-radius: 0.5rem; display: flex; justify-content: space-between; align-items: center; } button { background: #48a; color: white; border: none; border-radius: 0.3rem; padding: 0.3rem 0.6rem; cursor: pointer; } button:hover, button:focus { background: #357; outline: none; } </style>
The crossfade animation runs in about 400-500 milliseconds by default.
Time complexity depends on the number of items but is usually fast enough for typical UI lists.
Common mistake: forgetting to add a unique key to each list item, which breaks the animation.
Use crossfade when you want smooth transitions between list states. For simple fade in/out, use fade transition instead.
Crossfade makes list items smoothly move or fade when added, removed, or reordered.
Use send and receive functions from svelte/transition on list items.
Always provide unique keys to list items for correct animation.