Theme studio

Design a theme, preview it live, then export it. Saved in this browser.

Quick picks #10b981
Generated scale
50100200300400500600700800900
Some text is below AA

Pagination

  • Stable
  • WCAG 2.2 evidence
  • RTL

Moves through the pages of a list or table. A nav landmark with a named list of page buttons or links: the current page has aria-current="page", long lists collapse into ellipses (siblingCount, boundaryCount), previous, next, first and last have names, and controls at the end of the list stay focusable with aria-disabled so keyboard focus is not lost (WCAG 1.3.1, 2.1.1, 2.4.1, 2.4.7, 4.1.2). When the page changes without navigation, a polite status message names the new page (4.1.3). Targets are 32 px (40 px for mobile and load-more), 44 pt and 48 dp on touch platforms (2.5.8). Use it for tables and lists with stable page numbers; use CursorPager for cursor-based data and FeedStatus for infinite feeds. Consumer duties: a unique landmark name, the translated range text, and updating the content (and moving focus to it where that helps) when the page changes.

import { Pagination } from "@nexera-ui/react";
Loading example…
9
examples
21
props
1
live controls
1
platform
11
WCAG criteria
0
blocks use it

Try every prop. Copy the code.

Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.

Loading…
isLoading
Generated code
import { Pagination } from "@nexera-ui/react";

<Pagination />

Examples 8

The same examples as Storybook, rendered live. Open Code to copy one.

Types

Figma Type=Compact, Simple and Mobile, each wired to a page state.

Loading example…

Load more

Figma Type=Load more: appends content in place, keeps focus on the button and announces the new range.

Loading example…

Collapsing

siblingCount and boundaryCount decide how many numbers show; the list keeps the same length while paging. The first row is the default (1 and 1), the second shows only the current page between the boundaries, the third keeps two at each end.

Loading example…

Ends

The ends of the list: Previous and First are aria-disabled but stay focusable on page 1; Next and Last on the last page.

Loading example…

Narrow width

The Figma Pagination is 1000 px wide; here the row wraps inside a 320 px column instead of overflowing.

Loading example…

Long labels

Long translated strings and a long range wrap; nothing is truncated.

Loading example…

Right to left

Right to left: the list starts at the right, the glyphs mirror and Next points to the left.

Loading example…

Props 21

Press "Try it" on a card to load that prop into the playground.

21 props shown

pageNexera
number

Current page, from 1 (controlled). Use with onPageChange. Ignored by type="load-more".

Default –
defaultPageNexera
number

Page on first render (uncontrolled).

Default 1
onPageChangeNexera
(page: number) => void

Called with the new page when a control or page button is pressed.

Default –
rangeNexera
ReactNode

Text of the range, for example "11-20 of 128". You compute and translate it, so numbers, plural forms and digits match your locale. Shown by every type; it is announced politely when it changes with type="load-more".

Default –
captionNexera
ReactNode

Second line of the label under the range, type="mobile" only.

Default –
siblingCountNexera
number

Page numbers shown on each side of the current page (type="full"). Lower it where space is short; the list always keeps the same length while the user pages through it. Use {@link getPaginationRange } to see the entries.

Default 1
boundaryCountNexera
number

Page numbers always shown at the start and at the end (type="full").

Default 1
getPageHrefNexera
(page: number) => string

Makes the page controls links: getPageHref(page) is each address, for server-rendered or routed pages. Without it the controls are buttons and the page changes in place, which Pagination announces. Navigation announces itself.

Default –
pageSizeNexera
number

Rows per page (controlled, type="full"). Setting it (or defaultPageSize) shows the Figma Rows per page select; leave both out to hide it. Reset the page in your handler when the size changes.

Default –
defaultPageSizeNexera
number

Rows per page on first render (uncontrolled), which also shows the select.

Default –
onPageSizeChangeNexera
(pageSize: number) => void

Called with the size the user picked.

Default –
pageSizesNexera
readonly number[]

The choices of the rows-per-page select. The current size is added when missing.

Default [10, 20, 50, 100]
onLoadMoreNexera
() => void

type="load-more": called when the button is pressed.

Default –
isLoadingNexera
boolean

type="load-more": shows the spinner in the button, blocks presses and announces the state (Button isLoading).

Default false
progressNexera
number

type="load-more": the share of items loaded, 0 to 100. Shown as a decorative 200 x 4 bar; the range text carries the same information for assistive technology.

Default –
labelsNexera
Partial<PaginationLabels>

Strings the pagination invents (previous, next, first, last, page names, button texts). Translate them.

Default –
getPageAnnouncementNexera
(page: number, pageCount: number) => string

Text announced politely after the page changed in place (not for page links, nor type="load-more").

Default (page: number, pageCount: number): string => `Page ${String(page)} of ${String(pageCount)}`
typeNexera
"full" | "compact" | "simple" | "load-more" | "mobile"

Layout: full (rows per page, range, page numbers), compact (range, previous and next icons), simple (range, Previous and Next buttons), load-more (range, progress, Load more button) and mobile (previous, range label, next). mobile is a layout here, not a platform: touch sizes follow NexeraProvider.

Default full
pageCountNexera
number

Number of pages. Not needed by type="load-more".

Default 1
aria-labelNexera
string

Accessible name of the pagination landmark, for example "Employees". Say what is paged: a page with several nav landmarks needs a unique name for each. Translate it. Accessible name when it must differ from the visible text.

Default –
aria-labelledbyNexera
string

Id(s) of visible element(s) that name the landmark; wins over aria-label. Id(s) of visible element(s) that name the landmark, for example the heading of the table.

Default –

* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.

Accessible by default.

Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.

WCAG 2.2 evidence

8 direct · 3 supporting
  • 1.3.1Info and RelationshipsLevel A · tested directly
  • 1.3.2Meaningful SequenceLevel A · supporting test
  • 1.4.10ReflowLevel AA · supporting test
  • 1.4.12Text SpacingLevel AA · supporting test
  • 2.1.1KeyboardLevel A · tested directly
  • 2.4.1Bypass BlocksLevel A · tested directly
  • 2.4.3Focus OrderLevel A · tested directly
  • 2.4.4Link Purpose (In Context)Level A · tested directly
  • 2.5.3Label in NameLevel A · tested directly
  • 4.1.2Name, Role, ValueLevel A · tested directly
  • 4.1.3Status MessagesLevel AA · tested directly

Fits any width.

Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.

0 px · drag the corner

Styling hooks

Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.

  • data-hovered
  • data-pressed
Usage
<Pagination className="data-hovered:opacity-90 shadow-sm" />

Used in blocks

No block uses Pagination yet.

Related components