Pagination that never changes width as the reader walks through it: page numbers with ellipses kept to a fixed count, a marker that slides to the current page on a spring, and previous and next arrows that disable at the ends. Press an ellipsis and it opens into a small field to type any page and jump there. An optional page size menu keeps the first row on screen in view when the size changes, and a range readout says 21 to 40 of 312. Pages render as buttons, or as real links through your own router, and a narrow container collapses the numbers into Page 6 of 16.
The import and the props worth knowing about, in one place.
import { NavPagination } from "@/components/beste/component/nav-pagination";
// Buttons, controlled
<NavPagination total={312} pageSize={20} page={page} onPageChange={setPage} />
// Real links through your router, with a page size menu and the range readout
<NavPagination
total={312}
page={page}
pageSize={pageSize}
pageSizeOptions={[10, 20, 50]}
onPageSizeChange={setPageSize}
getHref={(page, size) => `/releases?page=${page}&size=${size}`}
renderLink={(props) => <Link {...props} />}
showRange
/>
// Two pages each side, two at each end, on a filled strip
<NavPagination pageCount={40} siblings={2} boundaries={2} tone="muted" size="lg" />Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Tab | Move through the arrows, the pages and the page size menu in order. |
|---|---|
| Enter / Space | Go to the focused page, or open an ellipsis into the go to page field. |
| Enter (in the field) | Jump to the typed page. Out of range marks the field invalid and keeps it open. |
| Escape | Close the go to page field without jumping. |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
total | number | — | Total number of items. Gives the page count with `pageSize`, and the range readout. |
pageCount | number | — | Page count, when you have it directly. Wins over `total`. |
page | number | — | Current page, one-based. Pair with `onPageChange` to control it. |
defaultPage | number | 1 | |
onPageChange | (page: number) => void | — | |
pageSize | number | — | Items per page. Pair with `onPageSizeChange` to control it. |
defaultPageSize | number | 10 | |
onPageSizeChange | (pageSize: number) => void | — | |
pageSizeOptions | number[] | — | Offer a page size menu with these choices. Two or more show it. |
siblings | number | 1 | Pages shown on each side of the current one. |
boundaries | number | 1 | Pages always shown at each end. |
getHref | (page: number, pageSize: number) => string | — | Render pages as links to these addresses instead of buttons. |
renderLink | (props: PaginationLinkProps) => React.ReactNode | — | Render the links through your router, e.g. `(props) => <Link {...props} />`. |
showLabels | boolean | — | Write "Previous" and "Next" beside the arrows. |
showRange | boolean | — | Show "21 to 40 of 312". Needs `total`. |
align | "start" | "center" | "end" | "center" | |
labels | Partial<typeof DEFAULT_LABELS> | — | Words used by the component, for translation. |
tone | "muted" | "outline" | "ghost" | "ghost" | |
size | "sm" | "default" | "lg" | "default" | |
disabled | boolean | — | |
aria-label | string | "Pagination" | |
className | string | — |