Page through long lists. Numbered pages with a stable width, a table footer bar with "1–20 of 312" and rows per page, SEO-friendly links, and cursor paging for APIs without a total.
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { Pagination, PaginationBar } from "@vamos-ui/react";
<Pagination page={page} pageCount={52} onPageChange={setPage} />
<PaginationBar total={312} page={page} pageSize={20} onPageChange={setPage} onPageSizeChange={setPageSize} />Moving focus to the top of the list after a page change is your app's job — focus the table caption or heading.
Examples
Table footer (HR)
PaginationBar formats the range with Intl and the locale. Changing the page size keeps the first visible row on screen.
| Employee | Role | ID |
|---|---|---|
| Ayşe Demir | Account executive | E-1001 |
| Jonas Weber | Support lead | E-1002 |
| Priya Nair | Product designer | E-1003 |
| Lucas Martin | Payroll specialist | E-1004 |
| Sofia Rossi | Account executive | E-1005 |
1–5 of 312
Variants and sizes
numbers, compact ("3 / 24") and simple (Previous / Next). Below 640px numbers shows as compact through CSS.
Links for SEO (blog archive)
getHref renders real links through the app's router Link, so crawlers can follow every page.
Cursor-based (CRM)
CursorPagination for APIs that only know whether there is a next page. The pressed button shows the spinner.
Loading
loading puts a spinner on the current page and locks the controls until the next page arrives.
API
Pagination
| Prop | Type | Default |
|---|---|---|
pageRequired. Current page, 1-based. | number | — |
pageCountRequired. Number of pages. | number | — |
onPageChangeCalled with the requested page. | (page: number) => void | — |
getHrefRender links instead of buttons (websites, SEO). | (page: number) => string | — |
siblingCountPages on each side of the current one. | number | 1 |
boundaryCountPages always shown at the start and end. | number | 1 |
variantNumbered, "3 / 52" with arrows, or Previous / Next. | "numbers" | "compact" | "simple" | "numbers" |
sizemd follows --control-h. | "sm" | "md" | "md" |
hideOnSinglePageRender nothing when pageCount ≤ 1. | boolean | true |
loadingSpinner on the current page; controls locked. | boolean | false |
labelsOverrides: label, previous, next, previousPage, nextPage, goTo ("Page {page}"), page, range, pageSize, morePages, empty. | Partial<PaginationLabels> | — |
PaginationBar
| Prop | Type | Default |
|---|---|---|
totalRequired. Total rows. | number | — |
pageSizeRequired. Rows per page. | number | — |
pageSizeOptionsChoices for rows per page; [] hides the picker. | number[] | [10, 20, 50, 100] |
onPageSizeChangeShows the rows-per-page picker when set. | (size: number) => void | — |
page · onPageChange · size · labels · getHrefAs on Pagination; pageCount is computed. | — | — |
CursorPagination
| Prop | Type | Default |
|---|---|---|
hasPrev · hasNextRequired. Enable the buttons. | boolean | — |
onPrev · onNextCalled on click. | () => void | — |
loadingLocks both; spinner on the pressed one. | boolean | false |
statusText between the buttons. | ReactNode | — |
usePaginationRange / paginationRange
| Prop | Type | Default |
|---|---|---|
{ page, pageCount, siblingCount?, boundaryCount? }Returns the items to render: numbers plus "ellipsis-start" / "ellipsis-end". Constant length while paging. | PaginationRangeOptions | — |
Primitives
| Prop | Type | Default |
|---|---|---|
PaginationList · PaginationItemLayout parts. | ul · li | — |
PaginationLinkRouter Link with href, otherwise a button. | { href?; isActive?; disabled?; loading? } | — |
PaginationPrevious · PaginationNextArrows (flip in RTL), named "Previous page" / "Next page". | PaginationLink + { showLabel? } | — |
PaginationEllipsis"…" announced as "More pages". | span | — |