Skip to content

Pagination

Page numbers with previous and next buttons, for content split across pages. Long ranges collapse to the first page, the last page, and the pages around the current one.

Navigationv0.1.0experimentalWCAG 2.2 AAView spec
import { Pagination } from "@rdloom/react";

export default function PaginationBasicExample() {
  return <Pagination pageCount={10} />;
}

Installation

npx rdloom add pagination

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/pagination.json

Works, but without upgrade tracking.

Usage

import { Pagination } from "@rdloom/react";

<Pagination pageCount={10} />

Many pages

import { Pagination } from "@rdloom/react";

// Far from the ends, both sides collapse to an ellipsis.
export default function PaginationManyPagesExample() {
  return <Pagination pageCount={200} defaultPage={100} siblingCount={1} />;
}

Controlled

Showing results 21 to 30

import { useState } from "react";
import { Pagination } from "@rdloom/react";

// After the page changes, tell people what changed: here a polite live region.
export default function PaginationControlledExample() {
  const [page, setPage] = useState(3);
  const pageCount = 12;
  return (
    <div className="flex flex-col items-center gap-3">
      <p aria-live="polite" className="text-sm">
        Showing results {(page - 1) * 10 + 1} to {page * 10}
      </p>
      <Pagination pageCount={pageCount} page={page} onChange={setPage} size="sm" />
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
pageCountrequired

Total number of pages.

numbernone
page

Controlled current page, starting at 1.

numbernone
defaultPage

Initial page when uncontrolled.

number1
onChange

Called with the page the user chose.

(page: number) => voidnone
siblingCount

How many page numbers to show on each side of the current page before collapsing the rest to an ellipsis.

number1
label

Accessible name of the navigation landmark. Translate it for other languages.

string"Pagination"
size

Button size.

"sm" | "md""md"
isDisabled

Disables every button.

booleanfalse

Accessibility

Role navigation, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

  • Tab moves between the buttons
  • Enter or Space goes to that page

Screen readers announce

  • Announced as a navigation landmark named Pagination, with a list of items
  • The current page is announced as the current page, e.g. "Page 3, current page"
  • A disabled previous button on page 1 is announced as dimmed or unavailable

What your code must do

  • A navigation landmark with an accessible name, containing a list of buttons
  • The current page has aria-current="page" and is also marked by shape and weight, not just color
  • Each page button is named Page N; previous and next are named Previous page and Next page and are disabled at the ends
  • Ellipses are decorative (aria-hidden)
  • After the page changes, move focus or announce the new content: the component only tells you the page

Guidelines

Use it when

  • Lists or search results split into pages
  • When people need to jump to a specific page or know how far they are

Avoid it when

  • Endless feeds: use a Load more button
  • A data grid: it has its own pager

Don't

  • Changing the content without telling screen readers (move focus to the results heading or announce it)
  • Hiding the current page number

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-action-primary
  • --rd-color-action-on-primary
  • --rd-color-surface-subtle
  • --rd-color-border-default
  • --rd-color-text-default
  • --rd-color-text-muted
  • --rd-color-focus-ring
  • --rd-radius-control