Pagination
Page navigation in the seam grouped-control language: links sit in a debossed well and the current page rises as an embossed key, springing to whichever page you pick.
Click a page — the embossed key springs to it (an instant jump under reduced motion).
tsx
"use client"
import * as React from "react"
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/registry/seam/ui/pagination"
// Controlled pagination: the embossed key springs to the page you pick.
export default function PaginationDemo() {
const [page, setPage] = React.useState(2)
const last = 12
const go = (p: number) => (e: React.MouseEvent) => {
e.preventDefault()
setPage(p)
}
return (
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
href="#"
disabled={page === 1}
onClick={go(page - 1)}
/>
</PaginationItem>
{[1, 2, 3].map((p) => (
<PaginationItem key={p}>
<PaginationLink href="#" isActive={p === page} onClick={go(p)}>
{p}
</PaginationLink>
</PaginationItem>
))}
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive={page === last} onClick={go(last)}>
{last}
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationNext
href="#"
disabled={page === last}
onClick={go(page === last ? page : page + 1)}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
)
}bunx --bun @seamui/cli@latest add paginationAPI
| Prop | Type | Default | Description |
|---|---|---|---|
| isActive | boolean | — | On PaginationLink — the current page: embossed key, aria-current="page". |
| disabled | boolean | — | On any link — non-navigable prev/next at the range ends (aria-disabled, unfocusable). |
| size | "icon" | "default" | "icon" | On PaginationLink — square page key, or a wide key for labelled prev/next. |
Links are plain <a> elements — pass href for real navigation or onClick for controlled state.
Notes
- The tabs/toggle-group idea again: a debossed well (
shadow-well) holds the keys and the active page is embossed (shadow-resting), springing between links via a shared layout animation — a static jump under reduced motion. - Page keys are links, not buttons — they wear
buttonVariantsdirectly so the pagination nav keeps real link semantics (aria-current, native navigation). - Committing a page change fires the
tickhaptic; re-clicking the active page doesn't. - For table pagination wired to TanStack state, Data Table ships its own footer — this component is for page-level navigation.
Press feedback, reduced motion, and haptics follow the global policy — see Motion and Haptics.