Pagination
Page-by-page navigation across a long, splittable set of results.
@garn/ui/paginationDefault
Previous · 1 2 3 · ellipsis · Next, page 2 active.
Installation
garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.
npx garn-ui add pagination- Registry
pagination- Source
- pagination.tsx
- Deps
lucide-react- Registry deps
buttonutils
Import
import { Pagination } from "@garn/ui/pagination";Props
Generated from the component's TypeScript types.
The root has no props of its own — it's a thin wrapper over its native element. Its parts carry the API:
PaginationLink
active- Description
- Marks the current page — `aria-current="page"` + a `data-active` reflect.
- Type
boolean
Plus 289 inherited native HTML attributes.
Styling
Target these data-slots and remap these tokens to restyle without forking the component.
[data-slot="pagination"]| Property | Token | Tier |
|---|---|---|
itemGap | --garn-gap-inline | semantic · air |
ellipsisSize | --garn-control-h-md | semantic · air |
Overview
Pagination splits a long, ordered result set into pages and lets users move between them. Pagination is the nav landmark, PaginationContent the list, PaginationLink each page number (active sets aria-current), with PaginationPrevious/PaginationNext controls. Use it when users benefit from stable, addressable pages (search results, tables); for continuously-growing feeds, infinite scroll or a "load more" button often fits better.
Guidelines
Choose pagination when position and addressability matter. Numbered pages let users bookmark, jump, and sense the set's size — ideal for results and data tables. For exploratory, endless feeds, consider load-more/infinite scroll instead.
Mark the current page and disable the ends. active carries aria-current="page"; disable Previous on page one and Next on the last page rather than letting them dead-end. Show enough context (first/last, neighbors, an ellipsis) without a giant row of numbers.
Keep it a labelled, keyboard-navigable nav. It's a navigation landmark — every control needs an accessible name ("Go to page 3", "Next page"). Pair it with a clear "N–M of T" indicator so users know where they are in the set.
Best practices
- Mark the current page's link with
active(sets aria-current="page" and data-active). - Collapse long ranges with PaginationEllipsis rather than rendering every number.
- Wrap your router's Link via PaginationLink for real client navigation.
- Don't render every page number for huge ranges — collapse the middle.
- Don't show pagination for a single page of results.
- Don't leave the boundary ambiguous — convey when Previous/Next are unavailable.
Content guidelines
- Label Previous/Next clearly and convey when they're unavailable.
- Keep page numbers plain; for huge ranges, collapse the middle with an ellipsis.
Accessibility
- Role
navigation
Keyboard
| Tab | Move between page links and the previous/next controls. |
| Enter | Follow the focused page link. |
- • The root <nav> is labeled "pagination" so it's a distinct landmark.
- • The active page link sets aria-current="page" (via `active`).
- • Previous/Next carry their own aria-labels; the ellipsis is aria-hidden with an sr-only label.
- Status
- Stable
- Version
v0.3.0- Introduced
v0.1.0
garn doesn't yet record a per-release version history. This reflects the component's current lifecycle state; full changelog entries will appear once the metadata pipeline emits a lifecycle.history field.