Skip to main content
The crossfade function creates a pair of transitions called send and receive. When an element is ‘sent’, it looks for a corresponding element being ‘received’, and generates a transition that transforms the element to its counterpart’s position and fades it out. When an element is ‘received’, the reverse happens. If there is no counterpart, the fallback transition is used. This is useful for creating smooth transitions between lists, such as a todo list where items move between “active” and “completed” states.

Usage

<script>
	import { crossfade } from 'svelte/transition';
	import { quintOut } from 'svelte/easing';

	const [send, receive] = crossfade({
		duration: 400,
		easing: quintOut
	});

	let todos = [
		{ id: 1, done: false, text: 'Learn Svelte' },
		{ id: 2, done: false, text: 'Build an app' }
	];
</script>

<div class="active">
	{#each todos.filter(t => !t.done) as todo (todo.id)}
		<div in:receive={{ key: todo.id }} out:send={{ key: todo.id }}>
			{todo.text}
		</div>
	{/each}
</div>

<div class="done">
	{#each todos.filter(t => t.done) as todo (todo.id)}
		<div in:receive={{ key: todo.id }} out:send={{ key: todo.id }}>
			{todo.text}
		</div>
	{/each}
</div>

Parameters

The crossfade function accepts a configuration object with the following parameters:
delay
number
default:"0"
Milliseconds before starting the transition
duration
number | function
default:"(d) => Math.sqrt(d) * 30"
Duration of the transition in milliseconds, or a function that takes the distance (in pixels) between the two elements and returns a duration
easing
function
default:"cubicOut"
An easing function that controls the animation curve
fallback
function
A transition to use when there is no matching element. Receives (node, params, intro) and should return a TransitionConfig

Return value

The crossfade function returns a tuple [send, receive] containing two transition functions. Each transition function is used with the in: and out: directives and requires a key parameter to match corresponding elements:
in:receive={{ key: someId }}
out:send={{ key: someId }}

Complete example

<script>
	import { crossfade } from 'svelte/transition';
	import { quintOut } from 'svelte/easing';
	import { fade } from 'svelte/transition';

	const [send, receive] = crossfade({
		duration: 300,
		easing: quintOut,
		// Fallback for elements without a counterpart
		fallback: (node, params) => fade(node, { duration: 200 })
	});

	let items = [
		{ id: 1, list: 'a', text: 'Item 1' },
		{ id: 2, list: 'a', text: 'Item 2' },
		{ id: 3, list: 'b', text: 'Item 3' }
	];

	function move(id, targetList) {
		items = items.map(item =>
			item.id === id ? { ...item, list: targetList } : item
		);
	}
</script>

<div class="lists">
	<div class="list">
		<h2>List A</h2>
		{#each items.filter(i => i.list === 'a') as item (item.id)}
			<div
				in:receive={{ key: item.id }}
				out:send={{ key: item.id }}
				on:click={() => move(item.id, 'b')}
			>
				{item.text}
			</div>
		{/each}
	</div>

	<div class="list">
		<h2>List B</h2>
		{#each items.filter(i => i.list === 'b') as item (item.id)}
			<div
				in:receive={{ key: item.id }}
				out:send={{ key: item.id }}
				on:click={() => move(item.id, 'a')}
			>
				{item.text}
			</div>
		{/each}
	</div>
</div>