Table of Contents
Creating the Segments
Making breadcrumbs base on routes is straightforward. In SvelteKit, +page.server.ts
, +page.ts
, +layout.server.ts
, and +layout.ts
load functions have an event parameter with an async parent()
method that returns data from parent +layout.server.ts
and +layout.ts
load functions.
By placing a breadcrumbs
array in the root layout, you can use event.parent()
and Array.concat
to append breadcrumbs at each route segment which requires a breadcrumb. And you can use data from that route segment to make the breadcrumb value and href dynamic.
Here is an example used on my Adventurers League Log Sheet app.
Root layout
// src/routes/+layout.server.ts
export const load = async (event) => {
return {
breadcrumbs: [] as { name: string; href: string }[],
};
};
First breadcrumb segment
// src/routes/characters/+layout.server.ts
export const load = async (event) => {
const parent = await event.parent();
return {
breadcrumbs: parent.breadcrumbs.concat(
{
name: "Characters",
href: `/characters`
}
)
};
};
Next breadcrumb segment with param
// src/routes/characters/[characterId]/+layout.server.ts
import { getCharacter } from "$/server/data/characters";
import { error, redirect } from "@sveltejs/kit";
export const load = async (event) => {
const parent = await event.parent();
if (event.params.characterId === "new") throw redirect(301, "/characters/new/edit");
const character = await getCharacter(event.params.characterId);
if (!character) throw error(404, "Character not found");
return {
breadcrumbs: parent.breadcrumbs.concat(
{
name: character.name,
href: `/characters/${character.id}`
}
)
};
};
Now the resulting array in data.breadcrumbs
for /characters/[characterId]
is:
[
{ name: 'Characters', href: '/characters' },
{ name: 'Rimurus', href: '/characters/cl7gfkggq002009mluw41peqd' }
]
The Breadcrumbs Component
From there, you can create a breadcrumbs component like this:
<!-- src/lib/components/Breadcrumbs.svelte -->
<script lang="ts">
import { page } from "$app/stores";
import Icon from "./Icon.svelte";
let breadcrumbs = ($page.data.breadcrumbs as { name: string, href?: string }[]).map((bc, i) => ({
name: bc.name,
href: !bc.href || i === $page.data.breadcrumbs.length - 1 ? null : bc.href,
}));
</script>
<div class="breadcrumbs mb-4 hidden flex-1 text-sm sm:flex">
<ul>
<li>
<Icon src="home" class="w-4" />
</li>
{#each breadcrumbs as bc}
{#if bc.href}
<li>
<a href={bc.href} class="text-secondary">
{bc.name}
</a>
</li>
{:else}
<li class="overflow-hidden text-ellipsis whitespace-nowrap dark:drop-shadow-md">
{bc.name}
</li>
{/if}
{/each}
</ul>
</div>