Pagination
Control bar navigating partitioned datasets across indexed pages.
Pagination
Pagination partitions large, dense datasets into manageable index pages. It provides users with clear spatial awareness of dataset size, current item range, and responsive controls to navigate forward, backward, or adjust page size.
In Hashti, Pagination renders as an accessible <nav> landmark with live region item counting, disabled edge boundaries, and an integrated native select dropdown for page size configuration.
Import
import { Pagination, NativeSelect, paginationRange } from "@hashti/react";
Examples
Basic Pagination
Configure pagination by specifying totalItems, the current page (1-indexed), the pageSize, and the onPageChange callback:
import { useState } from "react";
import { Pagination } from "@hashti/react";
export function BasicPaginationExample() {
const [currentPage, setCurrentPage] = useState(1);
return (
<div className="space-y-4 max-w-2xl">
<div className="p-6 border border-subtle rounded bg-layer-1 text-sm">
Displaying records for page <strong>{currentPage}</strong>...
</div>
<Pagination totalItems={100} page={currentPage} pageSize={10} onPageChange={setCurrentPage} />
</div>
);
}
With Page Size Selector
Provide onPageSizeChange and pageSizes to enable users to toggle how many records are displayed per page:
import { useState } from "react";
import { Pagination } from "@hashti/react";
export function PageSizePaginationExample() {
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(20);
return (
<div className="space-y-4 max-w-2xl">
<Pagination
totalItems={250}
page={page}
pageSize={pageSize}
pageSizes={[10, 20, 50, 100]}
onPageChange={setPage}
onPageSizeChange={(newSize) => {
setPageSize(newSize);
setPage(1); // Reset to page 1 when size changes
}}
/>
</div>
);
}
Table & Pagination Integration
Combine <Table> and <Pagination> for a full data browsing experience:
import { useState } from "react";
import { Table, TableHeader, TableBody, Column, Row, Cell, Pagination } from "@hashti/react";
const allRecords = Array.from({ length: 47 }, (_, i) => ({
id: `svc-${i + 1}`,
name: `service-node-${String(i + 1).padStart(2, "0")}`,
region: i % 2 === 0 ? "me-central-1" : "eu-west-1",
requests: `${(Math.random() * 50 + 10).toFixed(1)}k req/s`,
}));
export function TablePaginationExample() {
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(5);
const start = (page - 1) * pageSize;
const currentRecords = allRecords.slice(start, start + pageSize);
return (
<div className="space-y-3">
<Table aria-label="Microservices Fleet">
<TableHeader>
<Column isRowHeader>Node Name</Column>
<Column>Cluster Region</Column>
<Column>Incoming Request Rate</Column>
</TableHeader>
<TableBody items={currentRecords}>
{(item) => (
<Row id={item.id}>
<Cell>{item.name}</Cell>
<Cell>{item.region}</Cell>
<Cell>{item.requests}</Cell>
</Row>
)}
</TableBody>
</Table>
<Pagination
totalItems={allRecords.length}
page={page}
pageSize={pageSize}
pageSizes={[5, 10, 20]}
onPageChange={setPage}
onPageSizeChange={(size) => {
setPageSize(size);
setPage(1);
}}
/>
</div>
);
}
Standalone NativeSelect
The <NativeSelect> component used internally by Pagination is also exported for lightweight, native HTML select controls:
import { useState } from "react";
import { NativeSelect } from "@hashti/react";
export function NativeSelectExample() {
const [region, setRegion] = useState("tehran");
return (
<div className="max-w-xs">
<NativeSelect
label="Data Center Region"
value={region}
onChange={(e) => setRegion(e.target.value)}
description="Select the closest edge cluster to your users."
>
<option value="tehran">Tehran (IR-THR-1)</option>
<option value="isfahan">Isfahan (IR-ISF-1)</option>
<option value="shiraz">Shiraz (IR-SHR-1)</option>
<option value="frankfurt">Frankfurt (EU-FRA-1)</option>
</NativeSelect>
</div>
);
}
Props Reference
Pagination Props
| Prop | Type | Default | Description |
|---|---|---|---|
totalItems | number | Required | The total number of items across the entire dataset. |
page | number | Required | The current active page number (1-indexed). |
pageSize | number | Required | The number of records displayed per page. |
onPageChange | (page: number) => void | Required | Callback fired when the previous or next navigation button is pressed. |
pageSizes | number[] | [10, 20, 50] | Options populated in the items-per-page select dropdown. |
onPageSizeChange | (size: number) => void | — | Callback fired when the user selects a new page size. When omitted, the page size dropdown is hidden. |
aria-label | string | 'Pagination' | Accessible landmark label for the pagination <nav>. |
className | string | — | Additional CSS class names. |
NativeSelect Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | ReactNode | Required | Visible label associated with the native <select> element. |
size | 'sm' | 'md' | 'lg' | 'md' | Height and padding density of the select input. |
description | ReactNode | — | Supporting helper text rendered beneath the select. |
errorMessage | ReactNode | — | Validation error text. When present, marks the select invalid. |
disabled | boolean | false | Whether the select input is disabled. |
Accessibility (a11y)
- Navigation Landmark: The pagination bar renders as a semantic
<nav aria-label="Pagination">, making it discoverable through screen reader landmark navigation menus. - Polite Live Range Counter: The item summary span (
1–10 of 100 items) is marked witharia-live="polite". When users navigate between pages, the newly updated item range is read aloud without disrupting other announcements. - Button States:
- The “Previous page” button is automatically assigned
isDisabled={page <= 1}. - The “Next page” button is assigned
isDisabled={page >= pages}. - Disabled buttons are announced as disabled and removed from the active keyboard tab cycle.
- The “Previous page” button is automatically assigned
- Keyboard Navigation: Buttons and the page size selector are fully focusable and activatable via standard Tab, Enter, and Space keys.
Keyboard Interactions
| Key | Action |
|---|---|
| Tab | Moves focus through pagination buttons and select field. |
| Enter / Space | Activates next, previous, or numbered page. |
WAI-ARIA & Data Attributes
| Attribute | Target | Description |
|---|---|---|
[data-hovered] | Page Button | Present on pointer hover. |
[data-selected] | Page Button | Active on current active page button. |
[data-disabled] | Page Button | Applied when button reaches first or last page boundary. |