Pagination

Links to the pages of a long list: Previous, the page numbers, Next.

Installation

npx @yolkui/cli add pagination

When the page number lives in the URL, pass href with {page} standing for the number. Every page is then a real link: it opens in a new tab, can be shared, and a search engine can follow it. Without href the pages are buttons and onPageChange tells you which one was chosen.

Many pages

The first and last page always stay, and three dots stand for the pages left out. The row takes the same seven places on every page, so it never changes width and Next stays under the pointer while you click through. Below the sm breakpoint it shows five places and Previous and Next keep only their arrows, so it fits a 320px phone.

Sizes

size takes Button's four sizes: xs, sm, default and lg, 28 to 40 high. A row of buttons beside it at the same size lines up.

Under a table

Say what is shown at the start and put the pages at the end. The row centres itself in the space it is given; className="mx-0 w-auto" lets it sit at one side.

Showing 21–40 of 187 invoices

In a narrow place

The row reads the width of the screen, not of the box it sits in. In a card or a side panel on a wide screen, compact gives the five places and the arrows without words at every width.

With a router

renderLink takes your router's link, so a page changes without a reload. It reads its address from href, so this works in a server page too. A function that returns the link works from a client component.

The parts

Leave out page and total and write the items yourself. PaginationLink is a link; isActive marks the current page, and disabled draws one that goes nowhere.

Right to left

Under dir="rtl" the row starts at the right and the chevrons turn around. The words and the names a screen reader hears are props, so they can be translated.

API

Pagination draws the whole row from these props. Every part also takes className and the props of its element.

PropTypeWhat it does
pagenumberThe current page, from 1, when you hold it yourself.
defaultPagenumberThe page to start on when the row holds it. 1 by default.
totalnumberHow many pages there are. With it, the row is drawn for you.
onPageChange(page) => voidCalled with the page that was chosen.
hrefstring or (page) => stringThe address of a page; {page} in the text stands for the number. Makes every page a link.
renderLinkelement or (page) => elementYour router's link. An element takes its address from href.
compactbooleanFive places and arrows without words at every width.
siblingsnumberPages shown on each side of the current one. 1 by default.
sizexs · sm · default · lgButton's sizes.
previousText · nextTextstringThe words on the two ends. "Previous" and "Next".
previousLabel · nextLabel · getPageLabelstring · (page) => stringWhat a screen reader hears: "Go to previous page", "Go to next page", "Page 3".
PaginationLinkaOne page. isActive, disabled, size, and render for a router's link or a button.
PaginationPrevious · PaginationNextaThe two ends: a chevron and text.
PaginationEllipsisspanThree dots where pages are left out.
getPaginationRange(page, total, siblings?)The list of pages and "ellipsis" the row shows, for a row you build yourself. Call it from a client component.

Accessibility

The row is a nav landmark named "Pagination" holding a list, so a screen reader can jump to it and hears how many items there are.

  • The current page carries aria-current="page" and wears a border, so colour is never its only sign.
  • A page number is read as "Page 3", and the two ends as "Go to previous page" and "Go to next page", also on a phone where only their arrows show.
  • On the first page Previous has nowhere to go: it fades, is read as dimmed, stays in the Tab order and does nothing. The same for Next on the last page. Keyboard focus stays on it when it turns inactive.
  • The three dots are decoration and are hidden from screen readers.
  • With several nav landmarks on a page, each needs its own name: translate or change it with aria-label.
  • After a page changes, move focus or the scroll position to the top of the new results yourself; the row cannot know where they start.