Skip to content

Pagination

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

Basic Pagination

View 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

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 with aria-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