Skip to main content

Breadcrumbs

4 min readStableBeginner

Breadcrumbs sit above every page in the doc layout, built from the current route instead of from anything you write in the page. Each URL segment becomes one crumb, so readers can see where they are and click back up a level.

Quick Start

Save a page anywhere under app/ and its trail appears on its own. A file at app/features/api/api-blocks.mdx serves /features/api/api-blocks, which splits into three crumbs behind a house icon that links to the site root.

Route: /features/api/api-blocks
Plain Text
Home / Features / API / API Blocks

Labels come from formatSegmentLabel() in lib/format-segment.ts. It splits the segment on hyphens, formats each word, and joins the words with spaces. The same helper names the sidebar entries, so a page reads the same in both places.

Adding Options

Casing is not a plain capitalize. formatSegmentLabel() checks every word against a list of roughly 120 acronyms and product names, and a match renders in its canonical form — API, JWT, FAQ, MCP, SQL, OAuth, GraphQL, SaaS, TypeScript, MongoDB. Everything else gets an initial capital and a lowercased tail.

Acronym segments keep their canonical casing
Plain Text
/faq                     -> Home / FAQ
/api-reference/pet       -> Home / API Reference / Pet
/features/platform/mcp-server
                         -> Home / Features / Platform / MCP Server

Two more rules apply before the words are joined. A two-digit sort prefix is stripped, so 01-introduction shows as Introduction and keeps the sidebar ordering out of the reader's way. And a word longer than two characters that already mixes upper and lower case is passed through untouched, which is how a segment like openAPI survives.

Route: /getting-started/01-introduction
Plain Text
Home / Getting Started / Introduction

Deeper paths simply add crumbs. On /features/platform/table-of-contents, the first three crumbs link to their own routes and the last renders as plain text carrying aria-current="page".

Route: /features/platform/table-of-contents
Plain Text
Home / Features / Platform / Table Of Contents

Advanced

The trail is also emitted as BreadcrumbList JSON-LD next to the article, so search engines index the hierarchy. Home takes position 1 and each route segment follows in order.

One thing to know before you compare the two: the JSON-LD builder in app/[[...slug]]/page.tsx runs its own simple capitalizer rather than formatSegmentLabel(). It uppercases the first letter of each hyphen-separated word and leaves the rest alone, so api-blocks becomes Api Blocks in the structured data while the rendered crumb reads API Blocks. It also keeps a two-digit sort prefix that the visible label drops.

BreadcrumbList JSON-LD for /features/platform/breadcrumbs
JSON
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://docs.example.com"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Features",
      "item": "https://docs.example.com/features"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Platform",
      "item": "https://docs.example.com/features/platform"
    },
    {
      "@type": "ListItem",
      "position": 4,
      "name": "Breadcrumbs",
      "item": "https://docs.example.com/features/platform/breadcrumbs"
    }
  ]
}

Three edge cases round out the behavior. The site root renders no breadcrumb at all, because the component returns null for /. An archived version route carries its version segment as the first crumb, so /v1/getting-started reads Home / V1 / Getting Started. And an index.mdx page shows its directory as the last crumb, since the route stops at the directory name.

To teach the formatter a new acronym, add the word in its canonical casing to PRESERVE_UPPERCASE in lib/format-segment.ts. Matching is case-insensitive, so one entry covers every spelling that appears in a URL.

Options

route segmentsstring[]Default: current route

One crumb per path segment, read from usePathname(). Nothing in the page file changes them.

acronym casinglookupDefault: PRESERVE_UPPERCASE

A word matching the list renders in its canonical casing — API, JWT, FAQ, MCP, OAuth, GraphQL, SaaS, MongoDB, and about 110 more. Comparison ignores case.

mixed-case wordsstringDefault: passed through

A word over two characters that already mixes upper and lower case keeps its original spelling instead of being re-capitalized.

plain wordsstringDefault: Capitalized

Anything else gets an initial capital and a lowercased tail, with hyphens rendered as spaces.

numeric prefixstringDefault: stripped

A leading two-digit sort prefix such as 01- is removed from the label.

home crumblinkDefault: /

A house icon at the head of the trail, always linking to the site root.

current crumbbooleanDefault: true

The last crumb renders as text with aria-current="page" rather than a link.

landmarkstringDefault: Breadcrumb

The trail is an ordered list inside a nav labelled aria-label="Breadcrumb" so screen readers can jump to or skip it.

Was this page helpful?