Generate Breadcrumbs from Astro URL


A breadcrumb list shows a webpage’s position a website’s page hierarchy. Each breadcrumb links to a page in the hierarchy, allowing users to more easily navigate a website. Google can display breadcrumbs directly in search results.

Breadcrumb visual example

We use structured metadata in the head of a webpage to tell search engines what our breadcrumb list is. With Astro’s url object, we can generate this metadata automatically at build-time.

Recipe

  1. Create a Head component to hold your breadcrumb structured data.
Head.astro
<head>
<title>Page Title</title>
<meta name="description" content="Description of the page." />
</head>
  1. Retrieve the Astro.url of the current page in your Head component. Astro.url.origin is the base url for the website. Astro.url.pathname is the relative path to the current page.
Head.astro
---
const origin = Astro.url.origin;
const path = Astro.url.pathname;
---
<head>
<title>Page Title</title>
<meta name="description" content="Description of the page." />
</head>
  1. Split the path into a list of route names.
Head.astro
---
const { origin, pathname } = Astro.url;
let currentPath = origin + "/";
const breadcrumbData = pathname
.split("/")
.filter((s) => s.length > 0)
.map((pathname, index) => {
currentPath += index == 0 ? pathname : "/" + pathname;
return {
"@type": "ListItem",
position: index + 1,
name: pathname,
item: currentPath,
};
});
---
<head>
<title>Page Title</title>
<meta name="description" content="Description of the page." />
</head>
  1. Filter out any empty strings created by leading and trailing slashes.
Head.astro
---
const { origin, pathname } = Astro.url;
let currentPath = origin + "/";
const breadcrumbData = pathname
.split("/")
.filter((s) => s.length > 0)
.map((pathname, index) => {
currentPath += index == 0 ? pathname : "/" + pathname;
return {
"@type": "ListItem",
position: index + 1,
name: pathname,
item: currentPath,
};
});
---
<head>
<title>Page Title</title>
<meta name="description" content="Description of the page." />
</head>
  1. The breadcrumb metadata requires a list of objects representing each level in the path. Always set @type to "ListItem". Position is the index of the object starting at 1. The name field will be displayed in the generated breadcrumb menu. The item field holds the URL for each level of the path.

    Generate an array of ListItem objects from pathname using the map function.

Head.astro
---
const { origin, pathname } = Astro.url;
let currentPath = origin + "/";
const breadcrumbData = pathname
.split("/")
.filter((s) => s.length > 0)
.map((pathname, index) => {
currentPath += index == 0 ? pathname : "/" + pathname;
return {
"@type": "ListItem",
position: index + 1,
name: pathname,
item: currentPath,
};
});
---
<head>
<title>Page Title</title>
<meta name="description" content="Description of the page." />
</head>
  1. The final structured data must have three fields: @context, @schema, and itemListElement. The first two fields are constants, and the third field holds the breadcrumbData list we created.

    We create the data object structuredData, stringify it, and use Astro’s set:html function to render it in our Head component. Our structured data will be added with a script tag of type application/ld+json, which Google recommends.

Head.astro
---
const { origin, pathname } = Astro.url;
let currentPath = origin + "/";
const breadcrumbData = pathname
.split("/")
.filter((s) => s.length > 0)
.map((pathname, index) => {
currentPath += index == 0 ? pathname : "/" + pathname;
return {
"@type": "ListItem",
position: index + 1,
name: pathname,
item: currentPath,
};
});
const structuredData = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: breadcrumbData
};
---
<head>
<title>Page Title</title>
<meta name="description" content="Description of the page." />
<script type="application/ld+json" set:html={JSON.stringify(structuredData)} />
</head>
  1. Call your Head component in your layout or page.
BaseLayout.astro
---
import Head from "@components/Head.astro";
---
<!doctype html>
<html>
<Head />
<body>
<main>
<slot />
</main>
</body>
</html>