v0.5

Pagination

Numbered navigation for splitting long lists across pages.

Description

Pagination is a compound component that renders a <nav role="navigation" aria-label="pagination"> containing numbered links and direction controls. It is composed of PaginationContent, PaginationLink, PaginationEllipsis, and four directional buttons (PaginationFirst, PaginationPrevious, PaginationNext, PaginationLast). The compact-grouped variant delegates to ButtonGroup for a single connected surface; the compact variant lays the controls out as standalone buttons with gaps.

Reach for it on long tables, search results, archives, and report views where the user needs to scan ranges and jump to specific pages. Pair it with a row-count or page-size selector when the surface has room. The visible page set is yours to decide: a typical pattern is first, a window around the current page, an ellipsis, and last.

Don't use Pagination for infinite-scroll feeds (no controls needed), for switching between sibling panels (use Tabs), or for hierarchical trails like Home / Library / Albums (use Breadcrumb). A single back / forward pair without numbered pages is better served by two Buttons.

Installation

pnpm dlx @create-ui/cli add pagination

Anatomy

<Pagination>
  <PaginationContent>
    <PaginationFirst />
    <PaginationPrevious />
    <PaginationLink />
    <PaginationEllipsis />
    <PaginationNext />
    <PaginationLast />
  </PaginationContent>
</Pagination>

Usage

import {
  Pagination,
  PaginationContent,
  PaginationEllipsis,
  PaginationFirst,
  PaginationLast,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "@/components/ui/pagination"
<Pagination>
  <PaginationContent>
    <PaginationPrevious />
    <PaginationLink isActive>1</PaginationLink>
    <PaginationNext />
  </PaginationContent>
</Pagination>

Examples

Variants

variant picks between two layouts. compact-grouped (default) delegates to ButtonGroup, fusing every control into one connected surface with shared borders. compact renders the same controls as standalone buttons separated by small gaps, useful when the pagination sits on a busy surface where the grouped look feels heavy.

Shape

shape controls corner radius on both variants. rounded (default) follows the size scale; pill makes every control fully rounded. pill reads well on cards and toolbars; rounded fits table footers and dense layouts.

With Jump Buttons

Add PaginationFirst and PaginationLast at the ends when the range is long enough that jumping to the extremes saves clicks. For short ranges (under ~5 pages) the jump buttons are overkill; rely on PaginationPrevious and PaginationNext alone.

Disabled at Boundaries

Pass the native disabled attribute to mark directional buttons as unavailable. The typical pattern: disable PaginationFirst and PaginationPrevious on page 1, and PaginationNext and PaginationLast on the last page. Visuals (pointer, color, focus) come from the underlying button.

Controlled

Drive the current page from a useState and pass isActive to the matching PaginationLink. Each control wires its own onClick to move state, and the directional buttons clamp to 1 and total. Build your visible page window however you want; a 1 ... n-1 n n+1 ... total pattern covers most table views.

Page 3 of 10

Every clickable part accepts asChild, so you can hand off rendering to a router link (<a href>, next/link, react-router's Link) without losing the styling or ARIA wiring. When using asChild on PaginationLink, set aria-current="page" on the inner anchor for the active page so it still announces correctly.

Accessibility

Pagination renders a real <nav> with aria-label="pagination", so screen readers announce it as a navigation landmark. Each directional button (First, Previous, Next, Last) ships with a built-in aria-label. The active PaginationLink writes aria-current="page" automatically when isActive is set, and PaginationEllipsis is marked role="presentation" with a paired .sr-only "More pages" hint.

KeyDescription
TabMoves focus to the next control in the pagination.
Shift + TabMoves focus to the previous control.
Enter / SpaceActivates the focused link or button.

ARIA notes:

  • The root sets role="navigation" and aria-label="pagination"; do not wrap it in another nav landmark.
  • The active page is identified with aria-current="page". When using asChild on PaginationLink, mirror that attribute on the inner anchor so it survives the slot swap.
  • PaginationFirst, PaginationPrevious, PaginationNext, and PaginationLast set descriptive aria-labels ("Go to first page", etc.). Override with your own aria-label for localized copy.
  • For long, dynamic ranges, announce page transitions on the page region the pagination controls (e.g. set aria-live="polite" on the result list), not on the pagination itself.

Styling

Tailwind override: pass className to merge Tailwind classes with the component's CVA classes (via cn()):

<Pagination className="w-full justify-between">

Data slots and attributes: the component sets these for CSS targeting:

  • data-slot="pagination" on the root <nav>, with data-variant="<variant>" and data-shape="<shape>".
  • data-slot="pagination-content" on the inner wrapper (forwarded to ButtonGroup when variant="compact-grouped").
  • data-slot="pagination-link" on numbered links, with data-active when isActive is set.
  • data-slot="pagination-first", data-slot="pagination-previous", data-slot="pagination-next", data-slot="pagination-last" on the matching directional buttons.
  • data-slot="pagination-ellipsis" on the truncation marker.

Target a specific state in CSS:

[data-slot="pagination-link"][data-active] {
  /* style the active page */
}
  • ButtonGroup: the primitive that the compact-grouped variant delegates to; use it directly for non-numbered segmented controls.
  • Tabs: use this when the controls switch between sibling content panels in place rather than paging through a list.
  • Breadcrumb: use this for hierarchical location trails, not paged sequences.
  • Button: use a single Prev / Next pair (two Buttons) when there are no numbered pages to render.

API Reference

Pagination

The root container. Renders a <nav role="navigation" aria-label="pagination">, broadcasts variant and shape to every part through context, and writes data-slot="pagination" plus data-variant and data-shape. Extends React.ComponentProps<"nav">, so any standard <nav> attribute (id, role, aria-*, onClick, etc.) is accepted.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-A single PaginationContent holding the controls.

Variants

VariantOptionsDefaultDescription
variant"compact" "compact-grouped""compact-grouped"Layout treatment. compact-grouped delegates to ButtonGroup; compact uses standalone buttons.
shape"rounded" "pill""rounded"Corner radius. pill makes every control fully rounded.

PaginationContent

The inner wrapper that holds the controls. When variant="compact-grouped", this renders a ButtonGroup with variant="soft", size="md", and the shape inherited from the root. Otherwise it renders a <div> with inline-flex items-center gap-1. Writes data-slot="pagination-content". Extends React.ComponentProps<"div">.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-The directional buttons, numbered links, and ellipses, in order.

A numbered page link. Renders as a <button> by default; pass asChild to swap in an anchor or router link. Writes data-slot="pagination-link", data-active when isActive is set, and aria-current="page" for the active page. Extends Omit<React.ComponentProps<"button">, "type">.

Props

PropTypeDefaultDescription
isActivebooleanfalseMarks this link as the current page. Drives data-active and aria-current="page".
asChildbooleanfalseRender as the child element via Radix Slot. Use to swap in an anchor or router link.
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-The page numeral (or an anchor wrapping the numeral when asChild is set).

PaginationFirst

Directional button that jumps to the first page. Ships with aria-label="Go to first page" and a built-in RiArrowLeftDoubleFill icon. Override the icon by passing children. Writes data-slot="pagination-first". Extends Omit<React.ComponentProps<"button">, "type">.

Props

PropTypeDefaultDescription
asChildbooleanfalseRender as the child element via Radix Slot. Use to swap in an anchor or router link.
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-Optional override for the default icon.

PaginationPrevious

Directional button that steps one page back. Ships with aria-label="Go to previous page" and a RiArrowLeftSLine icon. Writes data-slot="pagination-previous". Extends Omit<React.ComponentProps<"button">, "type">.

Props

PropTypeDefaultDescription
asChildbooleanfalseRender as the child element via Radix Slot. Use to swap in an anchor or router link.
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-Optional override for the default icon.

PaginationNext

Directional button that steps one page forward. Ships with aria-label="Go to next page" and a RiArrowRightSLine icon. Writes data-slot="pagination-next". Extends Omit<React.ComponentProps<"button">, "type">.

Props

PropTypeDefaultDescription
asChildbooleanfalseRender as the child element via Radix Slot. Use to swap in an anchor or router link.
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-Optional override for the default icon.

PaginationLast

Directional button that jumps to the last page. Ships with aria-label="Go to last page" and a RiArrowRightDoubleFill icon. Writes data-slot="pagination-last". Extends Omit<React.ComponentProps<"button">, "type">.

Props

PropTypeDefaultDescription
asChildbooleanfalseRender as the child element via Radix Slot. Use to swap in an anchor or router link.
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-Optional override for the default icon.

PaginationEllipsis

Non-interactive truncation marker. Renders a <span role="presentation" aria-hidden="true"> containing the visible glyph and an .sr-only "More pages" hint. Writes data-slot="pagination-ellipsis". Extends React.ComponentProps<"span">.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode"..."Optional override for the visible glyph (the screen-reader hint is always rendered).