Skip to content

Pagination

Moves between the pages of a paged list. Each number renders as a Button.

tsx
import { Pagination } from 'neba';

<Pagination count={24} page={page} onPageChange={setPage} showEdges />;

Props

PropTypeDefaultDescription
localestringBCP 47 tag: the nav name, the page buttons, the arrows and the status sentence
variantshared'solid' | 'outline' | 'text''text'How the pages look at rest. The current page is always solid: the one thing the row has to say without being read, which is also why the default here is text: nine filled buttons in a row say all nine are the primary action
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'The buttons’ height and type scale. They are real Buttons, so a lg pagination lines up with a lg button beside it
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'Semantic colour role. Arbitrary colour values are not accepted
densityshared'default' | 'compact''compact'Padding only: never the height, never the type scale
elevationshared0 | 1 | 2 | 30Drop shadow depth. 0 means no shadow at all
count * numberHow many pages there are. Fewer than two and the whole control renders nothing: a row advertising that it has nothing to do is not a control
pagenumberThe current page, 1-based, for a controlled set
defaultPagenumber1Which page starts current
onPageChange(page: number) => voidCalled when the page changes
siblingCountnumber1How many pages are always shown on either side of the current one
boundaryCountnumber1How many pages are always shown at each end. 0 drops the first and last page, leaving only the window
showEdgesbooleanfalseShows the jump-to-first and jump-to-last steppers
showArrowsbooleantrueShows the previous and next steppers
disabledbooleanfalseUnavailable. Every button in the row stops answering
getPageHref(page: number) => stringThe address of a page. Turns the numbers into real links a crawler can follow, and marks the two arrows rel="prev" / rel="next"
labelstringAccessible name of the nav landmark
pageLabel(page: number) => stringAccessible name of a page button. Defaults to the locale's wording
previousLabelstringAccessible name of the previous stepper
nextLabelstringAccessible name of the next stepper
firstLabelstringAccessible name of the first-page stepper
lastLabelstringAccessible name of the last-page stepper

A count of 1 renders nothing at all.

Examples

variant

variant is how the page buttons look when they are not the current page. The current page is always filled, whatever the variant.

The default is text rather than Button's solid: several filled buttons in a row leave no way to tell which page you are on.

siblingCount · boundaryCount · showEdges · showArrows

siblingCount is how many numbers show either side of the current page; boundaryCount how many always show at each end. showEdges adds first/last buttons and showArrows adds previous/next.

The number of slots in the row stays constant as the page changes. The window slides toward whichever end it is near rather than being clipped by it, so the buttons never move out from under the pointer that just pressed one. A gap of exactly one page is filled with that page rather than an ellipsis.

size

getPageHref

Return the address of a page and the numbers in the row become real <a href>. A crawler cannot press a button, so without this everything past page one of a list does not exist to a search engine. The browser's own behaviour comes back with it: open in a new tab, copy the address, see where a press goes before making it. The two arrows carry rel="prev" and rel="next".

Pass onPageChange alongside it and the navigation is cancelled for the handler to answer: the shape a client-side router wants, keeping the page it already has. With no handler, the link does what a link does. A press carrying a modifier key is always left to the browser.

The page being read and an arrow at the end of the row stay <button>. An <a> cannot be disabled, so one left as a link is one a keyboard still lands on and a crawler still follows.

Accessibility

  • Renders a <nav> around a <ul>, with aria-current="page" on the current page.
  • The ellipsis is punctuation rather than a control, so it is not rendered as a disabled button.
  • With getPageHref the numbers are links, so they appear in a screen reader's list of links and a keyboard reader can see where each one goes.
  • Every accessible name is settable: label · pageLabel · previousLabel · nextLabel · firstLabel · lastLabel. With more than one pagination on a screen, use label to say what each one paginates.
  • locale decides the nav name, the page buttons, the arrows and the sentence that reads out where you are. Each of them takes a string of its own.

Released under the MIT License