Animated breadcrumbs
Render the crumbs array with
Svelte's built-in crossfade, fly and flip. This is what drives the
breadcrumb bar above — toggle "Animate breadcrumbs" in the sidebar to watch it.
Full example
Crumbs sit in a CSS grid, one column each, so flip can reposition the ones that
stay while crossfade pairs those
entering and leaving. A staggered fly fallback covers crumbs with no counterpart.
<script lang="ts">
import { crossfade, fly } from 'svelte/transition';
import { flip } from 'svelte/animate';
import { onMount } from 'svelte';
import { getCrumbs } from 'svelte-crumbs';
const crumbs = $derived(await getCrumbs());
let mounted = $state(false);
onMount(() => { mounted = true; });
let count = $derived(crumbs.length);
let prevCount = $derived(crumbs.length);
$effect.pre(() => {
prevCount = count;
count = crumbs.length;
});
const DURATION = 200;
const STAGGER = 60;
const [send, receive] = crossfade({
duration: 200,
fallback(node, _params, intro) {
if (!mounted) return { duration: 0 };
const i = parseInt(node.getAttribute('data-i') ?? '0');
const outTotal = (prevCount - 1) * STAGGER + DURATION;
const delay = intro
? outTotal + i * STAGGER
: Math.max(0, prevCount - 1 - i) * STAGGER;
return fly(node, intro
? { x: -4, duration: DURATION, delay }
: { y: 4, duration: DURATION, delay });
}
});
</script>
<nav
aria-label="Breadcrumbs"
class="grid auto-cols-auto items-center gap-2 text-sm"
>
{#each crumbs as crumb, i (crumb.url)}
<span
class="inline-flex items-center gap-2"
data-i={i}
style:grid-column={i + 1}
style:grid-row="1"
in:receive={{ key: crumb.url }}
out:send={{ key: crumb.url }}
animate:flip={{ duration: 150, delay: 150 }}
>
{#if i > 0}
<span aria-hidden="true">/</span>
{/if}
{#if i < crumbs.length - 1 || crumbs.length === 1}
<a href={crumb.url}>{crumb.label}</a>
{:else}
<span aria-current="page">{crumb.label}</span>
{/if}
</span>
{/each}
</nav>How it works
- Grid layout — each crumb is pinned to a column, so
flipanimates position changes as crumbs come and go. - Crossfade — a crumb in both the old and new trail morphs in place. Unmatched
crumbs fall back to
fly. - Staggered timing — outgoing crumbs leave last-first, then incoming crumbs arrive in order. The result cascades.
- SSR safe — the
mountedguard keeps transitions client-side.