Pagination

Links between the pages of a long list

Composablebuilt onButton

Pagination links the pages of a long list, like search results, tables, and feeds. A solid fill marks the current page and glides to the new one when it changes.

Preview

Installation

Usage

Composition

Mark the current page with isActive, and use isDisabled on Previous at the first page and Next at the last.

Examples

Page Range

Use getPaginationRange to get the pages and ellipses to show; it returns the same number of items for every page, so the row keeps its width.

Set siblingCount for pages beside the current one and boundaryCount for pages kept at each end. Both default to 1.

Pass render to use your router's link, so changing pages doesn't reload the document.

Variants

Use variant on PaginationContent to pick the shell around the links.

VariantDescription
outlineThe default. An outline Button's fill and border.
softA secondary Button's fill, no edge.
ghostNo shell.

Size

Use size on PaginationContent to match a Button of the same size.

Set [--radius:9999px] for a pill. Recolor the current page with --pagination-current-bg and --pagination-current-fg.

Compact

Use PaginationStatus between Previous and Next to show the position alone.

Accessibility

Landmark and current page

Pagination is a nav labeled "Pagination", and the current page's link has aria-current="page". In forced-colors mode the current page gets a Highlight border, since the fill disappears.

Previous and Next

Below the sm breakpoint they show only their arrows. Their label stays as the accessible name, so a custom or translated label carries through.

A disabled link leaves the tab order, blocks its click, and drops its href. A router link passed through render keeps the href it requires, but its click is still blocked.

Status and motion

PaginationStatus is a polite live region, so screen readers announce the new position. With reduced motion, the current-page fill moves without sliding.

API Reference

Pagination is a custom component built from plain HTML elements; every prop below is specific to it. Each part also accepts the props of the element it renders (nav, ul, li, a, or span).

Utilities

getPaginationRange

Takes { page, pageCount, siblingCount?, boundaryCount? } and returns page numbers, "start-ellipsis", and "end-ellipsis". The page clamps to 1..pageCount. In a Server Component, import it from pagination/lib/range, since the pagination module is a client module.

Props

PaginationContent

The list and its shell. Renders a ul.

A page link. Renders an a. PaginationPrevious and PaginationNext build on it and take the same props.

PaginationPrevious / PaginationNext

Links to the previous and next page, with an arrow.

Notes

PaginationEllipsis

Stands in for skipped pages. Renders a span that screen readers announce as "More pages".

PaginationStatus

A read-only position, like "Page 3 of 12". Renders an li that is a polite live region.

Upgrading

If you're reinstalling over an earlier version, check these changes:

BeforeNow
Installed as cubby-ui/pagination.tsxInstalls into a cubby-ui/pagination/ folder with pagination.css and lib/range.ts. Import from @/components/ui/cubby-ui/pagination/pagination and delete the old file.
Bare links, the current page an outline buttonA shell (outline by default) with a gliding fill. Use variant="ghost" for none.
PaginationLink took a sizeSet size once on PaginationContent.
aria-label="pagination" on navaria-label="Pagination", overridable.
Previous and Next had fixed accessible namesTheir label is the accessible name; it's visually hidden below sm.