ComponentsNavigation
Pagination
Composable pagination building blocks for navigating through pages of content
The Pagination component provides composable building blocks for page navigation. It renders semantic <nav> with aria-label="pagination" and uses anchor elements that work with any routing library. Pair with the usePagination helper to generate consistent page ranges with ellipsis.
Import
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
PaginationPrevious,
PaginationNext,
PaginationEllipsis,
usePagination,
} from '@nim-ui/components';Basic Usage
Code
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="?page=1" />
</PaginationItem>
<PaginationItem>
<PaginationLink href="?page=1">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="?page=2" isActive>2</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="?page=3">3</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href="?page=3" />
</PaginationItem>
</PaginationContent>
</Pagination>With usePagination Helper
The usePagination helper computes a page range with ellipsis markers based on the current page, total pages, and a sibling count:
import { usePagination } from '@nim-ui/components';
function MyPagination({ currentPage, totalPages, onPageChange }) {
const pages = usePagination({
totalPages,
currentPage,
siblingCount: 1,
});
return (
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
onClick={() => onPageChange(Math.max(1, currentPage - 1))}
/>
</PaginationItem>
{pages.map((page, i) => (
<PaginationItem key={i}>
{page === 'ellipsis' ? (
<PaginationEllipsis />
) : (
<PaginationLink
isActive={page === currentPage}
onClick={() => onPageChange(page)}
>
{page}
</PaginationLink>
)}
</PaginationItem>
))}
<PaginationItem>
<PaginationNext
onClick={() =>
onPageChange(Math.min(totalPages, currentPage + 1))
}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
);
}Example output
usePagination({ totalPages: 20, currentPage: 10, siblingCount: 1 })
// => [1, 'ellipsis', 9, 10, 11, 'ellipsis', 20]
usePagination({ totalPages: 5, currentPage: 3 })
// => [1, 2, 3, 4, 5]
usePagination({ totalPages: 20, currentPage: 2 })
// => [1, 2, 3, 'ellipsis', 20]Props
PaginationLink
| Name | Type | Default | Description |
|---|---|---|---|
isActive | boolean | false | Mark this page as the current/active page (sets aria-current="page") |
size | 'sm' | 'md' | 'lg' | 'md' | Size variant for the link button |
href | string | - | URL for the pagination link |
className | string | - | Additional CSS classes |
usePagination
| Name | Type | Default | Description |
|---|---|---|---|
totalPages* | number | - | Total number of pages |
currentPage* | number | - | Current active page (1-indexed) |
siblingCount | number | 1 | Number of sibling pages to show on each side of the current page |
showEdges | boolean | true | Always show the first and last page |
Accessibility
- Root is a
<nav>landmark witharia-label="pagination" - Active page has
aria-current="page" - Previous/Next buttons have descriptive
aria-labels - Ellipsis is
aria-hidden="true"with a screen-reader-only "More pages" text - Focus-visible rings use the primary token for consistent keyboard feedback