Pagination
Page navigation with items-per-page and result info
View MarkdownOverview
Pagination provides controls for moving through a paginated list: first/last and previous/next buttons, a windowed set of numbered page buttons, an optional “showing X to Y of Z” info line, and an optional items-per-page Select. It is a controlled component — you own the current page and page size, and it calls back when the user changes them.
It does not slice your data; it only renders the controls. Compute the current page’s items yourself from currentPage and itemsPerPage, and pass the counts in. To keep the UI uncluttered when pagination isn’t needed, the component renders nothing when totalItems is at or below the smallest items-per-page option.
totalItems vs. filteredItems
Two counts are required because they serve different purposes:
totalItems— the full, unfiltered size of the dataset. Used only to decide whether to render the controls at all.filteredItems— the number of items after any active filtering. Drives the page count, the info text, and the numbered buttons.
When no filtering is applied, pass the same value for both.
Usage
Import the component:
import { Pagination } from "@eqtylab/equality";
Hold the page and page size in state, slice your data from them, and wire the callbacks:
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(10);
const pageItems = allItems.slice(
(currentPage - 1) * itemsPerPage,
currentPage * itemsPerPage,
);
<Pagination
currentPage={currentPage}
totalItems={allItems.length}
filteredItems={allItems.length}
itemsPerPage={itemsPerPage}
onPageChange={setCurrentPage}
onItemsPerPageChange={setItemsPerPage}
type="items"
/>;
Changing the page size resets to page 1 automatically.
Default
Configuration
- Items-per-page dropdown — only shown when you pass
onItemsPerPageChange. Without it, the info line shows a static end count instead. Customise the choices withitemsPerPageOptions. - Info line — set
showInfo={false}to hide the “showing X to Y of Z” text. Usetypeto append a noun (e.g.type="items"→ “of 100 items”). - First/last jumps — double-chevron buttons bookend the navigation so users can jump straight to the first or last page. They appear only once there are more pages than
maxVisiblePages; while every page still has its own numbered button, they would duplicate it. SetshowFirstLast={false}to render only previous/next. - Windowing —
maxVisiblePagescontrols how many numbered buttons appear at once; the window slides to keep the current page centered. - Scroll on change — pass
scrollTargetRef(a ref or an elementidstring) to smooth-scroll that element into view whenever the page changes.
Props
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
currentPage | The active page (1-based). | number | — | ✅ |
totalItems | Full dataset size. Controls whether the component renders. | number | — | ✅ |
filteredItems | Item count after filtering. Drives page count and info text. | number | — | ✅ |
itemsPerPage | Number of items shown per page. | number | — | ✅ |
onPageChange | Called with the new page when the user navigates. | (page: number) => void | — | ✅ |
onItemsPerPageChange | Called with the new page size. When provided, the items-per-page dropdown is shown. | (itemsPerPage: number) => void | — | ❌ |
itemsPerPageOptions | Choices offered in the items-per-page dropdown. | number[] | [10, 25, 50, 100] | ❌ |
showInfo | Whether to show the “showing X to Y of Z” info line. | boolean | true | ❌ |
showFirstLast | Whether to show the jump-to-first and jump-to-last buttons when there are more pages than maxVisiblePages. | boolean | true | ❌ |
maxVisiblePages | Maximum number of numbered page buttons shown at once. | number | 5 | ❌ |
type | Noun appended to the info line (e.g. "items"). | string | "" | ❌ |
scrollTargetRef | Element (ref or id string) scrolled into view on page change. | RefObject<HTMLElement>, string | — | ❌ |
className | Additional CSS classes applied to the container. | string | — | ❌ |