AdminKitDocs
Navigation

React Bootstrap Breadcrumb

A React Bootstrap breadcrumb in JSX: show where a page sits in your app, with React Router links built from the current route and custom dividers.

Pro

This component is only available in AdminKit PRO. Learn more.

A breadcrumb shows where the current page sits in your app: Home, then Projects, then the project you are looking at. Each step above the current page is a link, so people can go back up a level in one click. It helps most on pages that are a few levels deep, such as a single invoice or a project's settings.

In AdminKit for React, a breadcrumb is Bootstrap's markup written in JSX. There is no component to import. The links are React Router Links, so moving up a level does not reload the page. Breadcrumbs are part of AdminKit PRO: the stylesheet of the free version leaves out Bootstrap's breadcrumb styles.

Example

Put an ordered list in a <nav>. Every step is a .breadcrumb-item, and the last one is the page you are on.

import { Link } from "react-router";

export function ProjectBreadcrumb() {
  return (
    <nav aria-label="breadcrumb">
      <ol className="breadcrumb">
        <li className="breadcrumb-item">
          <Link to="/">Home</Link>
        </li>
        <li className="breadcrumb-item">
          <Link to="/projects">Projects</Link>
        </li>
        <li className="breadcrumb-item active" aria-current="page">
          Website redesign
        </li>
      </ol>
    </nav>
  );
}

Classes

ClassElementEffect
breadcrumb<ol>Lays out the steps in a row, without list bullets
breadcrumb-item<li>One step; adds the divider before every step except the first
activethe last <li>Shows the current page in a muted color; add aria-current="page" too

AdminKit uses Bootstrap's breadcrumb as it is, without changes of its own. Bootstrap's docs have the full list of its Sass variables.

Writing the steps by hand works for a page or two. For every page, build them from the URL instead. useLocation() gives the current path. Each part of the path becomes a step, and each step links to the path up to that part.

The labels come from src/data/pages.json, the list of pages that also sets each page's title. getPage() from @/lib/site looks a path up there. A path that is not in the list, such as a project id, falls back to the text in the URL:

src/components/breadcrumbs.tsx
import { Link, useLocation } from "react-router";
import { getPage } from "@/lib/site";

export function Breadcrumbs() {
  const { pathname } = useLocation();
  const segments = pathname.split("/").filter(Boolean);

  const crumbs = [
    { path: "/", label: "Home" },
    ...segments.map((segment, index) => {
      const path = `/${segments.slice(0, index + 1).join("/")}`;
      return { path, label: getPage(path)?.title ?? decodeURIComponent(segment) };
    }),
  ];

  return (
    <nav aria-label="breadcrumb">
      <ol className="breadcrumb">
        {crumbs.map((crumb, index) =>
          index === crumbs.length - 1 ? (
            <li key={crumb.path} className="breadcrumb-item active" aria-current="page">
              {crumb.label}
            </li>
          ) : (
            <li key={crumb.path} className="breadcrumb-item">
              <Link to={crumb.path}>{crumb.label}</Link>
            </li>
          )
        )}
      </ol>
    </nav>
  );
}

Render <Breadcrumbs /> at the top of a page, above its PageTitle. On a path like /projects/42, it shows Home, Projects and 42, once /projects is in pages.json with the title Projects.

The demo's routes are one level deep, such as /pages-settings. There, the breadcrumb is Home and the page title. It grows as soon as your own routes nest.

AdminKit sets up React Router with <BrowserRouter> and <Routes> in src/app.tsx. Hooks such as useMatches() only work with a data router (createBrowserRouter), so useLocation() is the one to use here. The sidebar uses it too, to highlight the current page.

Dividers

The slash between the steps comes from CSS, not from your markup. To change it on one breadcrumb, set the --bs-breadcrumb-divider custom property on the <nav>. The value is a CSS string, so it keeps its own quotes:

<nav
  style={{ "--bs-breadcrumb-divider": "'>'" } as React.CSSProperties}
  aria-label="breadcrumb"
>
  <ol className="breadcrumb">
    <li className="breadcrumb-item">
      <Link to="/">Home</Link>
    </li>
    <li className="breadcrumb-item active" aria-current="page">
      Projects
    </li>
  </ol>
</nav>

TypeScript does not know custom properties in style, hence the cast. An empty string, "''", removes the divider. To change it for the whole app, set $breadcrumb-divider in src/scss/1-variables/_app.scss. That file loads before Bootstrap, so Bootstrap uses your value.

Accessibility

  • Wrap the list in a <nav> with an aria-label, so screen readers announce it as a navigation region.
  • Give the last step aria-current="page". The active class only changes its color.
  • Use an ordered list (<ol>): the order of the steps carries meaning.
  • The current page is plain text, not a link to itself.

Last updated on

On this page