const TOTAL_PAGES = /* ... */;
<Pagination>
<PaginationList>
<PaginationItem>
<PaginationPrevious
isDisabled={page === 1}
onPress={() => setPage((p) => Math.max(1, p - 1))}
/>
</PaginationItem>
{getPageRange(page, TOTAL_PAGES).map((p, i) =>
p === 'ellipsis' ? (
<PaginationItem key={`ellipsis-${i}`}>
<PaginationEllipsis />
</PaginationItem>
) : (
<PaginationItem key={p}>
<PaginationLink
isActive={p === page}
aria-label={`Page ${p}`}
onPress={() => setPage(p)}
>
{p}
</PaginationLink>
</PaginationItem>
),
)}
<PaginationItem>
<PaginationNext
isDisabled={page === TOTAL_PAGES}
onPress={() => setPage((p) => Math.min(TOTAL_PAGES, p + 1))}
/>
</PaginationItem>
</PaginationList>
</Pagination>Installation
npx shadcn@latest add @dotui/paginationUsage
Compose pagination from its parts. Provide an href on each link to navigate between pages, or wire onPress to drive client-side state.
import {
Pagination,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationList,
PaginationNext,
PaginationPrevious,
} from '@/components/ui/pagination'<Pagination>
<PaginationList>
<PaginationItem>
<PaginationPrevious href="#" />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>
2
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationList>
</Pagination>Anatomy
<Pagination>
<PaginationList>
<PaginationItem>
<PaginationPrevious />
</PaginationItem>
<PaginationItem>
<PaginationLink />
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext />
</PaginationItem>
</PaginationList>
</Pagination>Pagination is the nav landmark and PaginationList the ul that wraps each PaginationItem. PaginationLink is a page cell, PaginationPrevious and PaginationNext are the directional links, and PaginationEllipsis marks a gap of skipped pages.
State
Pagination holds no page state of its own — you own the current page. Wire onPress on each link to update it, pass isActive to the current page (which sets aria-current="page" and the active style), and isDisabled to cap the ends.
<PaginationPrevious isDisabled={page === 1} onPress={() => setPage(page - 1)} />
<PaginationLink isActive={page === n} onPress={() => setPage(n)}>
{n}
</PaginationLink>Framework Setup
PaginationLink, PaginationPrevious, and PaginationNext are built on the Link button, so they pick up router integration from your button.tsx — there's nothing pagination-specific to wire up. See the Button docs to connect LinkButton to your framework's router, and pagination links with an href will route through it automatically.
Examples
Links
Controlled with Smart Range
With Results Summary
Showing 1–10 of 42 results
Table with Pagination
Invoice | Customer | Amount |
|---|---|---|
| INV-001 | Acme Corp | $1,240.00 |
| INV-002 | Globex | $820.50 |
| INV-003 | Initech | $3,100.00 |
Page 1 of 3
API Reference
Pagination
Pagination lets users navigate through large sets of content split across multiple pages. It renders a `nav` landmark labelled "pagination".
Supports all nav attributes.
| Prop | Type | Default | |
|---|---|---|---|
PaginationList
PaginationItem
PaginationLink
A pagination link. Provide an `href` to navigate, or an `onPress` handler to drive client-side state. Built on top of the Link button, so it shares its `variant` and `size`.
| Prop | Type | Default | |
|---|---|---|---|
boolean | — | ||
union | isActive ? 'default' : 'quiet' | ||
union | "md" | ||
boolean | true | ||
ReactNode | function | — | ||
boolean | — | ||
PaginationPrevious
A link that navigates to the previous page. Renders a leading chevron and, unless `isIconOnly` is set, a "Previous" label hidden on small screens.
| Prop | Type | Default | |
|---|---|---|---|
ReactNode | — | ||
boolean | — | ||
boolean | — | ||
boolean | true | ||
union | "md" | ||
union | isActive ? 'default' : 'quiet' | ||
PaginationNext
A link that navigates to the next page. Renders a trailing chevron and, unless `isIconOnly` is set, a "Next" label hidden on small screens.
| Prop | Type | Default | |
|---|---|---|---|
ReactNode | — | ||
boolean | — | ||
boolean | — | ||
boolean | true | ||
union | "md" | ||
union | isActive ? 'default' : 'quiet' | ||
PaginationEllipsis
Last updated on 7/5/2026