/// Navigation
Pagination
Page navigation — a mono button row. Numbered mode draws pages with ellipses and an inverted current page; cursor mode draws prev/next only.
import { Pagination } from "@protocore/pds";Numbered (known total)
Pass pageCount for a fully numbered row. The current page inverts to a solid fill, and long ranges collapse to ellipses. Emit changes through onPageChange.
Showing settlements 51–75 of 300.
Cursor (unknown total)
Omit pageCount and pass hasPrev / hasNext for keyset-paginated data where the server never returns a total — you only know whether another page exists.
Message log — page 1
Wide ranges
siblingCount controls how many pages flank the current one before the range collapses. First and last pages always stay visible.
When to use it
Use Pagination to move through pages of a list or table under a fixed page size.
- Know the total count? Use numbered mode (
pageCount) so users can jump directly and see how far they are. - Backed by a cursor / keyset API with no cheap total? Use cursor mode (
hasPrev/hasNext) — never fake a page count. - Prefer infinite scroll for exploratory feeds; keep Pagination for addressable, bookmarkable pages (search results, ledgers, logs).
- It pairs naturally under a DataTable or ListingRow list.
Usage
Do
- Use cursor mode (hasPrev/hasNext) whenever the total is unknown or expensive to compute.
- Keep page size fixed while paging so offsets stay meaningful.
- Reflect the current page in the URL so a page is shareable and back-button-safe.
- Disable PREV/NEXT at the ends rather than hiding them, so the control's width is stable.
Don't
- Don't invent a pageCount you don't have just to show numbers.
- Don't reset to page 1 silently when a filter changes without telling the user.
- Don't stack Pagination with infinite scroll on the same list.
- Don't raise siblingCount so high the row overflows on mobile.
Accessibility
| Keys | Action |
|---|---|
| Tab | Move focus across PREV, the page buttons, and NEXT |
| Enter / Space | Activate the focused page button |
- The root is a `<nav aria-label="Pagination">` landmark; override the name with `aria-label` when several paginators share a page.
- The current page button carries `aria-current="page"`; PREV / NEXT have explicit `aria-label`s and are `disabled` at the ends.
Pagination props
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | — | Accessible name for the nav landmark. Default "Pagination". |
className | string | — | |
hasNext | boolean | — | Cursor mode: whether a next page exists. Ignored when `pageCount` is set. |
hasPrev | boolean | — | Cursor mode: whether a previous page exists. Ignored when `pageCount` is set. |
onPageChange | ((page: number) => void) | — | Called with the requested 1-based page. |
page * | number | — | Current page, 1-based. |
pageCount | number | — | Total page count. Omit for cursor mode (prev/next only). |
siblingCount | number | 1 | Numbered mode: pages to keep either side of the current page. Default 1. |
style | CSSProperties | — |