Pagination

Moves through pages of results.

Mode

Sizes

States

Usage

When to use it
Use
A list or a table too long for one page: jobs, runs, partitions.
Use
The person needs to say "page 4" or share a link to it.
Not for
A log that streams; let it scroll. Use Button.
Not for
Moving through the sections of one page. Use Numbered tabs.

Rules

6 rules
Must
Give every page an href with getHref or hrefPattern, even when onPageChange handles the click. Because a real link opens in a new tab and can be shared, and the page survives a reload.
Never
Mark the current page with the yellow slab or an edged box. Because the current page is where you are, so it takes the selection wash; the slab is for the one action.
Must
Leave out pages for a cursor API and pass hasNext. Because a made-up total promises pages that are not there.
Should
Pair it with PaginationInfo, saying the range and the total. Because the numbers say where you are; the range says what you are looking at.
Should
Use size="sm" in a frame's footer row. Because the 26px cells sit in a 40px row with clear space.
Never
Hide Previous on the first page or Next on the last. Because the row would shift, and the person aiming at Next would hit a number.

State order

5 states, highest first
1
current
2
disabled
3
focus-visible
4
hover
5
rest

Accessibility

4 checks
A nav named "Pagination"; the current page has aria-current="page".
Every page link is named "Page n"; Previous and Next keep their names when only the arrow shows.
The current page is text-1 on the selection wash at 16.4:1 and 11.7:1; the others text-2 at 7.8:1.
A disabled link has aria-disabled and no href, so it leaves the tab order.

Keyboard

2 keys
Tab
Moves through Previous, the pages and Next.
Enter
Follows the link.

Edge cases

5 edge cases
Page 1 of 1,204
Seven slots, each as wide as "1,204", so Next never moves.
Phone, 390 wide
Previous and Next become arrows; if the numbers still do not fit, "Page 4 of 24".
Cursor API
Previous, "Page 3" and Next.
Right to left
The arrows mirror and the pages run right to left.
Inside a flex row
It measures its own width, so give it one (w-full or a basis); it has no width from its content.

API

7 props
PaginationNav page
number
PaginationNav pages
number
PaginationNav hasNext
boolean
PaginationNav getHref, hrefPattern
function, string default '?page={page}'
PaginationNav onPageChange
(page, event) => void
PaginationNav size
'default' | 'sm' default 'default'
PaginationInfo from, to, total, noun
number, number, number, string

Tokens

13 tokens
--control
32px
--control-sm
26px
--selected
#fff4bf
--hover
rgb(22 21 18 / 0.04)
--pressed
rgb(22 21 18 / 0.08)
--type-label
400 13px/16px var(--font-mono)
--type-label-sm
400 12px/16px var(--font-mono)
--type-code-sm
400 12px/16px var(--font-mono)
--text-1
#161512
--text-2
#55524a
--text-3
#6b675e
--text-disabled
#a8a499
--space-4
16px

Install

For your coding agent

GitHub

Please star me pookie

198

A new design system every week

Leave your email before you copy the prompt.