Pagination

Steps through content split across numbered pages.

import { Pagination } from "@usefragments/ui";Source

Preview

<Pagination totalPages={10} defaultPage={1}>
  <Pagination.Previous />
  <Pagination.Items />
  <Pagination.Next />
</Pagination>

Usage

Use when

  • Data sets served a page at a time
  • Tables and lists with a known total
  • Search results past the first screen

Avoid when

  • Everything already fits on one page
  • Content that loads as the user scrolls
  • Switching between panels (use Tabs)
  • Steps in an order (use Stepper)

Implementation notes

  • Sit it directly below what it pages
  • The first and last page always show; siblingCount sets how many neighbours show
  • The current page takes the neutral current fill and ink 1, not the selection colour or the brand accent
  • Pass renderLink when each page has its own URL
  • The root forwards id, aria-*, data-*, and handlers to <nav>
  • A step's onClick runs first — call preventDefault() to stop the change

Installation

pnpm add @usefragments/ui

The npm package stays managed by your package manager. Import styles once from @usefragments/ui/styles. See the installation guide for framework and theme setup.

Anatomy

Import Pagination once, then compose its parts with dot notation.

  • Pagination.Previous
  • Pagination.Next
  • Pagination.Items

Neighbours around the current page, ends always reachable.

<Pagination totalPages={10} defaultPage={1}>
  <Pagination.Previous />
  <Pagination.Items />
  <Pagination.Next />
</Pagination>

Examples

Many Pages

The first and last page stay; gaps fold into an ellipsis.

<Pagination totalPages={20} defaultPage={10}>
  <Pagination.Previous />
  <Pagination.Items />
  <Pagination.Next />
</Pagination>

Compact

Drops the neighbours when space is tight.

<Pagination totalPages={20} defaultPage={10} siblingCount={0}>
  <Pagination.Previous />
  <Pagination.Items />
  <Pagination.Next />
</Pagination>

Controlled

You hold the page number in state.

<Pagination totalPages={5} page={3}>
  <Pagination.Previous />
  <Pagination.Items />
  <Pagination.Next />
</Pagination>

Each page is a link to its own URL.

<Pagination totalPages={8} defaultPage={3} renderLink={(page) => <a href={`?page=${page}`} />}>
  <Pagination.Previous />
  <Pagination.Items />
  <Pagination.Next />
</Pagination>

API reference

Component props
Prop
Type
Default
Description
childrenRequiredReact.ReactNodeNot setPagination.Previous, Pagination.Items and Pagination.Next
defaultPagenumber | undefined1Default page (uncontrolled)
onPageChange((page: number) => void) | undefinedNot setCalled when page changes
pagenumber | undefinedNot setControlled current page (1-indexed)
renderLink((page: number) => React.ReactElement) | undefinedNot setMakes every page a link: (page) => the element to render, such as an anchor or a router link. Pressing it still calls onPageChange
siblingCountnumber | undefined1Pages shown on each side of the current one; the first and last page always show
sizePaginationSize | undefinedsmmdNot setItem size; resolves through ComponentDefaults when omitted
totalPagesRequirednumberNot setTotal number of pages; renders nothing when there are none

Accessibility

  • Uses nav element with aria-label="Pagination"
  • aria-current="page" marks the current page
  • Previous/Next have descriptive aria-labels
  • Steps at the boundaries are disabled buttons, even in link mode
  • TablesiblingCommonly paired for table pagination
  • ListboxalternativeUse Listbox for small sets of options

Next steps