Askr documentation
UI & Components

Breadcrumb and Pagination

Breadcrumb and Pagination: anatomy, keyboard behavior, state, and theming in Askr.

Example

import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from '@askrjs/themes/components';

<Breadcrumb aria-label="Breadcrumb">
  <BreadcrumbList>
    <BreadcrumbItem><BreadcrumbLink href={projectsRoute}>Projects</BreadcrumbLink></BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem><BreadcrumbPage>{project.name}</BreadcrumbPage></BreadcrumbItem>
  </BreadcrumbList>
</Breadcrumb>

Purpose

Two small, unrelated-but-neighboring kits: `Breadcrumb` answers "where am I in the hierarchy," and `Pagination` answers "which page of results am I on." Both are plain markup/slot components — no routing awareness, no fetching, no page-count math baked in.

Install and import

```tsx import { Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis, } from '@askrjs/themes/breadcrumb'; import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationPrevious, PaginationNext, PaginationEllipsis, } from '@askrjs/themes/pagination'; ```

Live examples

The example composes `Breadcrumb` down to the current page, with `BreadcrumbPage` marking the last crumb rather than a link — that is what stops a screen reader announcing the page you are already on as somewhere to go. Build the intermediate `BreadcrumbLink` destinations from route parameters so the trail stays correct when the route shape changes.

Anatomy

`Breadcrumb` renders `<nav role="navigation">`, `BreadcrumbList` an `<ol>`, `BreadcrumbItem` an `<li>`, and `BreadcrumbLink` an `<a>`; `BreadcrumbPage` is a `<span>` for the current, non-linked crumb. `BreadcrumbSeparator` and `BreadcrumbEllipsis` default their children to `"/"` and `"..."` respectively. `Pagination` mirrors the same shape: `<nav role="navigation">` wrapping a `PaginationContent` `<ul>` of `PaginationItem` `<li>`s, with `PaginationLink`, `PaginationPrevious` (default label "Previous"), `PaginationNext` (default label "Next"), and `PaginationEllipsis` (default "...") as the individual `<a>`/`<span>` controls.

State model

Neither component knows which page or crumb is active on its own. For pagination, you pass `active` to `PaginationLink` yourself for the current page — it's the only prop that isn't purely cosmetic, and it drives both `aria-current` and a `data-active` attribute. For breadcrumbs, you simply render the last segment as `BreadcrumbPage` instead of `BreadcrumbLink`. Route state, current page number, and total-page math all live in your app code.

Keyboard and accessibility

Links are real `<a>` elements, so Tab and Enter work without any extra wiring. `BreadcrumbPage` sets `aria-current="page"` for you automatically; `PaginationLink` only sets it when you pass `active`. Both `BreadcrumbSeparator`/`BreadcrumbEllipsis` and `PaginationEllipsis` are marked `aria-hidden="true"` by default so screen readers skip the decorative slashes and dots rather than announcing them.

Styling and tokens

Each part exposes a matching `data-slot`: `breadcrumb`, `breadcrumb-list`, `breadcrumb-item`, `breadcrumb-link`, `breadcrumb-page`, `breadcrumb-separator`, `breadcrumb-ellipsis` on one side, and `pagination`, `pagination-content`, `pagination-item`, `pagination-link`, `pagination-previous`, `pagination-next`, `pagination-ellipsis` on the other. `PaginationLink` additionally exposes `data-active="true"` when it's the current page, which is the natural CSS hook for highlighting it.

API

All parts take the shared props — `as`, `asChild`, `class`, `children`, `ref`, plus passthrough attributes. The one addition worth knowing is `PaginationLink`'s `active?: boolean`. Separator and ellipsis components accept a `children` override if you want something other than the default `"/"` or `"..."` glyph.

Edge cases

Long breadcrumb trails don't auto-collapse — if you want a truncated trail with `BreadcrumbEllipsis` standing in for hidden segments, you decide when and where to insert it. Same for pagination with many pages: there's no windowing logic shipped, so figuring out where `PaginationEllipsis` belongs is your app's job. If a page has more than one `nav` landmark (say, both a breadcrumb and the primary navigation menu), give each an `aria-label` yourself since neither component sets one automatically, and screen reader users rely on that label to tell them apart.

Navbar and Navigation Menu for the primary nav bar these often sit under, Data Table for paginated tabular data, and Application Chrome for how breadcrumbs and pagination fit into a full page layout.