Pagination
AlphaAccessible pagination control. Renders a <nav> landmark with a labelled list of page buttons, optional First/Last buttons, an optional rows-per-page selector, and an optional Go to page input. Works fully controlled, fully uncontrolled, or mixed.
Import
import { Pagination } from "@compa11y/react";Usage
Example.tsx
import { Pagination } from "@compa11y/react";
// Uncontrolled (simplest)
function BasicExample() {
return <Pagination totalPages={24} />;
}
// Controlled
function ControlledExample() {
const [page, setPage] = useState(1);
return (
<Pagination
totalPages={24}
currentPage={page}
onPageChange={setPage}
/>
);
}
// Derived from totalItems
function DerivedExample() {
const [page, setPage] = useState(1);
return (
<Pagination
totalItems={312}
pageSize={25}
currentPage={page}
onPageChange={setPage}
/>
);
}
// Full-featured
function FullExample() {
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(25);
return (
<Pagination
totalItems={312}
currentPage={page}
onPageChange={setPage}
showFirstLast
showPageSize
pageSizeOptions={[10, 25, 50, 100]}
pageSize={pageSize}
onPageSizeChange={setPageSize}
showJumpTo
ariaLabel="Products pagination"
/>
);
}
// Disabled
function DisabledExample() {
return <Pagination totalPages={10} currentPage={1} disabled />;
}Features
- <nav> landmark wraps all controls; aria-label defaults to "Pagination" and is customisable via ariaLabel
- aria-current="page" on the active page button — no extra ARIA role needed
- aria-label on every button: "Page N", "Previous page", "Next page", "First page", "Last page"
- Native HTML disabled on buttons (not aria-disabled) for boundary and fully-disabled states
- Live region (role="status" aria-live="polite") announces "Page N of M" on navigation and page-size changes
- Ellipsis items carry aria-hidden="true" — purely visual
- Rows-per-page <select> is labelled via htmlFor / id
- Jump-to input uses aria-describedby for inline validation errors rendered in role="alert"
- Stable IDs via useId — safe when multiple instances share a page
- Controlled (currentPage / onPageChange), uncontrolled (defaultPage), and mixed modes
- Dev warnings when neither totalPages nor totalItems is supplied, or currentPage is out of range
Props
| Prop | Type | Default | Description |
|---|---|---|---|
totalPages | number | - | Total page count. Required unless totalItems is provided |
totalItems | number | - | Total item count; used to derive totalPages when totalPages is not set |
currentPage | number | - | Controlled current page (1-indexed) |
defaultPage | number | 1 | Initial page for uncontrolled usage |
onPageChange | (page: number) => void | - | Called when the active page changes |
ariaLabel | string | "Pagination" | aria-label for the <nav> landmark — must be unique when multiple instances appear on the same page |
siblingCount | number | 1 | Pages shown either side of the current page |
boundaryCount | number | 1 | Pages shown at each end of the range |
showFirstLast | boolean | false | Show First (««) and Last (»») buttons |
disabled | boolean | false | Disable all controls |
unstyled | boolean | false | Omit data-compa11y-* attributes and inline layout styles |
showPageSize | boolean | false | Render a rows-per-page <select> |
pageSize | number | - | Controlled page size |
pageSizeOptions | number[] | [10, 25, 50] | Options for the rows-per-page selector |
onPageSizeChange | (size: number) => void | - | Called when page size changes; component automatically resets to page 1 |
showJumpTo | boolean | false | Render a "Go to page" number input |
Keyboard Interactions
Accessibility
All keyboard interactions follow WAI-ARIA best practices and work without any additional configuration.
| Key | Action |
|---|---|
| Tab | Moves between all controls in DOM order |
| Enter / Space | Navigates to the focused page button |
| Enter | Submits the jump-to input; shows an inline error if the value is out of range |
CSS Customization
Override these CSS custom properties to customize the appearance.
| Variable | Description | Default |
|---|---|---|
--compa11y-pagination-color | Button text color | inherit |
--compa11y-pagination-bg | Button background | transparent |
--compa11y-pagination-border | Button border color | currentColor |
--compa11y-pagination-radius | Button border radius | 4px |
--compa11y-pagination-size | Minimum button width and height (touch target) | 44px |
--compa11y-pagination-current-bg | Current page button background | currentColor |
--compa11y-pagination-current-color | Current page button text color | canvas |
--compa11y-focus-color | Focus ring color | #0066cc |