Skip to main content
Graphite UI

Pagination

Moves a reader through a set too long for one page, either page by page or by number. Use the table bar under a Data table, and the page numbers under a list of results.

Contract 1.0.0Kit · 4 sets · 37 variantsOpen in Figma

Live preview

Rendered by the component itself from the same generated tokens as the rest of the site.

Installation

Install it with the shadcn CLI, along with everything it uses. New project? Set it up first, as Quick start shows.

npx shadcn@latest add https://www.graphite-ui.com/r/pagination.json
import { Pagination, PaginationNav } from '@/components/ui/pagination'

Anatomy

The table bar: items per page, the range shown, a page picker with its total, then previous and next, each section divided by a subtle rule. The page-number form is the kit’s second set: the arrows around the page items, the current one marked.

Items per page:1–20 of 243 itemsPageof 13 pages
  1. Previous and nextRequiredGhost icon-only Buttons at the bar's size, named "Previous page" and "Next page", disabled at the ends.
  2. Items per pageOptionalThe table bar's Advanced type. The governed Select, inline, labelled "Items per page:".
  3. RangeOptionalThe table bar's Advanced type. "1–100 of 100 items" in on-surface-variant, filling the middle.
  4. PageRequiredAdvanced draws a page picker (the governed Select with its label hidden) and its total, "of 10 pages"; Simple and Unbound draw "Page 1".

Variants

Size sets the row: 48, 40 or 32. The table bar has three types; Simple and Unbound look the same, and differ in whether the total is known.

Nav: Large
Nav: Medium
Nav: Small
Table bar: Advanced
Items per page:1–20 of 243 itemsPageof 13 pages
Table bar: Simple
Page 1
Table bar: Unbound
Page 1
Table bar: Small
Items per page:1–20 of 243 itemsPageof 13 pages

API reference

Generated from the contract, versioned with it, and checked by drift-check. This table cannot describe props the component does not have.

Pagination props
PropTypeDefaultNotes
type'advanced' | 'simple' | 'unbound'—The kit's Pagination - Table bar Type. Unbound is for a total that is not known, so Next follows hasNext. The kit draws Simple and Unbound identically.
size'sm' | 'md' | 'lg'—The kit's Size, a 32, 40 or 48 row. Large by default.
page / pageSize / pageSizes / totalItems / onChange——Controlled. onChange receives the next page and page size; changing the page size returns to page 1.
hasNextboolean—Unbound only.
page-number form——The kit's Pagination - Nav, a separate export. Square page items at the same three sizes between previous and next, the current page marked; at most itemsShown entries (seven, as the kit draws), the first and last pages always shown, and an ellipsis for each run left out, which opens those pages as a native select (the kit's Overflow item). Wrapped in a nav landmark.

Design tokens

Every swatch is live. Change the source color in the header and this table repaints, because it reads the same roles the component does.

  • elevationThe table bar, elevation-01 (the kit's layer-01); page-item and overflow hover, elevation-02 (the kit's background-hover).
  • outlineThe table bar's top rule and its section dividers, through the subtle step (outline-subtle, the kit's border-subtle-00).
  • on-surfacePage numbers, the page label and total.
  • on-surface-variantThe range text.
  • primaryThe current page's 16px rule (the kit's border-interactive), and the focus ring, through the family's focus step.
  • textBody/3, and Title/5 SemiBold for the current page.
  • spacingItem sizes, the bar's height and the section padding.

Usage

The contract's prohibitions, written as the choices you will actually face.

Do

  • Use the table bar under a Data table, in its footer slot, so the table and its pages read as one.
  • Use Unbound when the total is not known, and tell it whether there is a next page with hasNext.
  • Return to page 1 when the page size changes; the component does this for you.
  • Keep the page numbers short. Seven entries, ellipses included, is the kit’s window.

Don’t

  • Restyle the arrows or the pickers. They are the governed Button and Select.
  • Mark the current page by colour alone. It takes the weight and the rule, and aria-current.
  • Use pagination for a list short enough to show at once.
  • Put the page numbers in a table footer. That is the table bar’s place.

Accessibility

What the component does for you, and what it leaves to you.

Roles
The page numbers sit in a nav landmark, each item a button named “Page n”, the current one with aria-current="page". The table bar is a labelled group.
Keyboard
Tab reaches the arrows, the items and the pickers in order. The ellipsis is a native select, so the arrow keys move through the pages it hides.
Names
The arrows are “Previous page” and “Next page”; the page picker keeps “Page” as its name with the label hidden; the ellipsis names the range it hides.
Focus
The items take a 2px --graphite-primary-focus ring inside their square; the arrows and pickers bring their own.

Figma parity

The kit’s Pagination page has two public sets: Pagination - Nav and Pagination - Table bar. The code exports one component for each.

Kit axes and how they map to code
Kit axisValuesCodeHow it maps
SetPagination - NavPaginationNavSquare items between the arrows; the current page SemiBold with a 16px primary rule.
SetPagination - Table barPaginationOn elevation-01 with an outline-subtle top rule and dividers.
SizeLarge · Medium · Smallsize48, 40 and 32. The kit draws the bar 50, 42 and 34, two over its controls, the same +2 Button carries; built at the controls’ height plus the rule.
TypeAdvanced · Simple · UnboundtypeAdvanced: items per page, the range, the page picker and its total. Simple and Unbound: “Page n”. The kit draws the last two identically.
Nav: OverflowBooleanitemsShownThe ellipsis opens the hidden pages as a native select, the kit’s Overflow item and its menu.
Item stateEnabled · Hover · Focus · Selected—Hover (elevation-02) and Focus are pseudo-classes (governance rule 7); Selected is the current page.