Skip to content

Pagination

Pagination moves through the pages of a long list: arrows, page numbers with ellipses that jump over the hidden pages, and optionally a page size picker and a field to type a page. It is a <nav> landmark; the current page carries aria-current="page" and every item has a name (“Page 3”, “Next page”, “Jump forward to page 8”).

Demos

Basic

Simple

simple replaces the page list with a field holding the current page and the total. Type a page and press Enter or leave the field.

Page slot

pageSlot is how many slots the page list takes, ellipses included. Hover or focus an ellipsis to see which way it jumps.

Quick jumper

showQuickJumper adds a field to type a page. It jumps on Enter or on blur, clamped to the page range.

Size

small, medium and large match the control heights, so the size picker and the jumper line up with the pages.

Page size picker

With itemCount the page count follows from the page size. showSizePicker lets the user pick it from pageSizes; when larger pages leave fewer of them, the page moves back into range. Both page and pageSize can be controlled.

Disabled

Prefix and suffix

prefix and suffix take a node or a function of the pagination’s state: page, pageSize, pageCount, itemCount, startIndex and endIndex.

Custom arrows and labels

prev, next and goto replace the arrows and the jumper’s text; label renders a page or an ellipsis. The accessible names stay the same.

Display order

displayOrder orders the page list, the size picker and the quick jumper.

getHref(page) turns every page, arrow and ellipsis into an <a href>, so crawlers can follow the pages and a middle click opens one in a new tab. A plain click still calls onUpdatePage; a modified click only follows the link. The arrows get rel="prev" / rel="next", and a disabled arrow loses its href.

renderItem(props, info) renders each item yourself, e.g. with your router’s Link: spread props on it (class, accessible name, aria-current, href and the click handler). The handler runs first, so the router can still navigate without a reload.

Pagination Props

NameTypeDefaultDescriptionVersion
pagenumberundefinedCurrent page, from 1, when controlled.Unreleased
defaultPagenumber1Initial page when uncontrolled.Unreleased
onUpdatePage(page: number) => voidundefinedCalled with the new page.Unreleased
pageCountnumber1Total pages. Ignored when itemCount is set.Unreleased
itemCountnumberundefinedTotal items; the page count follows from it and the page size.Unreleased
pageSizenumberundefinedItems per page when controlled.Unreleased
defaultPageSizenumberfirst of pageSizes, else 10Initial page size when uncontrolled.Unreleased
onUpdatePageSize(pageSize: number) => voidundefinedCalled with the new page size.Unreleased
pageSizesArray<number | PaginationSizeOption>[10]Choices in the size picker. A number is labelled “10 / page”.Unreleased
showSizePickerbooleanfalseShows a page size picker.Unreleased
selectPropsPartial<SelectProps>undefinedMore props for the size picker’s Select.Unreleased
showQuickJumperbooleanfalseShows a field to type a page to go to.Unreleased
pageSlotnumber9How many slots the page list takes, ellipses included.Unreleased
simplebooleanfalseA field with the current page and the total instead of the page list.Unreleased
disabledbooleanfalseDisables every control.Unreleased
sizesmall | medium | largemediumItem, picker and field size.Unreleased
displayOrderArray<'pages' | 'size-picker' | 'quick-jumper'>['pages', 'size-picker', 'quick-jumper']Order of the parts.Unreleased
prefixReactNode | (info: PaginationInfo) => ReactNodeundefinedBefore everything.Unreleased
suffixReactNode | (info: PaginationInfo) => ReactNodeundefinedAfter everything.Unreleased
prevReactNode | (info: PaginationInfo) => ReactNodeundefinedReplaces the previous-page arrow.Unreleased
nextReactNode | (info: PaginationInfo) => ReactNodeundefinedReplaces the next-page arrow.Unreleased
gotoReactNode | () => ReactNodelocale’s “Go to”The quick jumper’s text.Unreleased
label(info: PaginationLabelInfo) => ReactNodeundefinedContent of a page or an ellipsis.Unreleased
getHref(page: number) => stringundefinedLink mode: items become <a href>.Unreleased
renderItem(props: PaginationItemProps, info: PaginationItemInfo) => ReactNodeundefinedRenders an item’s element yourself.Unreleased

Other attributes, such as aria-label, go to the root <nav>.

Types

ts
type PaginationInfo = { page: number; pageSize: number; pageCount: number; itemCount: number; // `itemCount`, or pageCount × pageSize startIndex: number; // first item on the page, from 0 endIndex: number; // last item on the page }; type PaginationLabelInfo = | { type: "page"; node: number; active: boolean } | { type: "fast-backward" | "fast-forward"; node: ReactNode; active: false }; type PaginationItemInfo = { type: "page" | "prev" | "next" | "fast-backward" | "fast-forward"; page: number; // where the item goes active: boolean; disabled: boolean; href: string | undefined; }; type PaginationItemProps = { "aria-current": "page" | undefined; "aria-disabled": true | undefined; "aria-label": string; children: ReactNode; className: string; href: string | undefined; rel: "prev" | "next" | undefined; onClick: (event: MouseEvent<HTMLElement>) => void; };

Notes

  • prefix, suffix, prev, next and goto take a node or a render function.
  • The ellipses jump on click and name their target page.
  • Sizes follow the control heights (28 / 34 / 40px), the same as the size picker and the jumper.