Pagination
Previous and Next with page numbers between them, for moving through a long list one page at a time.
ui.pagination
components/ui/pagination.tsxUse case
Use it under a long list read page by page: every invoice of the year, a client's order history, a log of activity. The current page is outlined and marked for screen readers; Previous and Next keep their arrows and drop their words on a phone. A list short enough to show whole needs none.
Use it when
- A table or list longer than a screen, read in pages
- The page number belongs in the address, so a link or a reload lands on the same page
- People jump to a page, not only to the next one
Use something else when
- Going up from a record to its list: Breadcrumb
- Sections of one record: Tabs
Examples
Code
Import
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination"Usage
export function InvoicePages({ page }: { page: number }) {
return (
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href={`?page=${Math.max(1, page - 1)}`} />
</PaginationItem>
{[1, 2, 3].map((n) => (
<PaginationItem key={n}>
<PaginationLink href={`?page=${n}`} isActive={page === n}>
{n}
</PaginationLink>
</PaginationItem>
))}
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href={`?page=${page + 1}`} />
</PaginationItem>
</PaginationContent>
</Pagination>
)
}Rules
- The current page's `PaginationLink` takes `isActive`: it sets `aria-current="page"` and the outlined style.
- Each link carries an `href` to its page; when the page is held in state instead, call `preventDefault` in `onClick` as the showcase does.
- Passing `render` to `PaginationLink` drops its button styles, so use `href` and `onClick` rather than a custom element.
- Keep the page inside its bounds in the handler (`Math.max(1, p - 1)`), and mark a gap in the numbers with `PaginationEllipsis` rather than listing every page.