ComponentsPagination
Pagination
Let users move between pages of results.
On this page
Use this component from the local workspace package. Follow the setup guide first. A public npm package and registry are not available yet.
View registry filesImport the component into your page or component file.
import {
Pagination,
getPaginationRenderItems,
} from "@dethink/components";Try the examples, then open the code to use them in your app.
Bounded callback controls
Known totals expose previous, next, first, last, current-page state, and deterministic ellipses.
Show sourceexamples/pagination/basic.tsx
"use client";
import { useState } from "react";
import { Pagination } from "@dethink/components";
export function PaginationBasic() {
const [page, setPage] = useState(4);
return (
<Pagination
aria-label="Example result pages"
page={page}
pageCount={12}
showFirstLast
onPageChange={setPage}
/>
);
}Route-backed links
Real page URLs with in-place navigation: the selected page follows the URL, browser Back/Forward works, and changing pages preserves your scroll position.
Show sourceexamples/pagination/link-mode.tsx
"use client";
import { Pagination } from "@dethink/components";
import { usePathname, useSearchParams } from "next/navigation";
import { Suspense } from "react";
function LinkedPagination() {
const pathname = usePathname();
const searchParams = useSearchParams();
const requestedPage = Number(searchParams.get("page") ?? 6);
const page =
Number.isSafeInteger(requestedPage) && requestedPage > 0
? Math.min(requestedPage, 18)
: 6;
return (
<Pagination
aria-label="URL result pages"
hrefForPage={(nextPage) => {
const params = new URLSearchParams(searchParams);
params.set("page", String(nextPage));
return `${pathname}?${params}`;
}}
onClick={(event) => {
// Keep copy-link, new-tab, and modified-click behavior native.
if (
event.defaultPrevented ||
event.button !== 0 ||
event.metaKey ||
event.ctrlKey ||
event.shiftKey ||
event.altKey
)
return;
const link =
event.target instanceof Element
? event.target.closest("a[href]")
: null;
if (
!(link instanceof HTMLAnchorElement) ||
link.hasAttribute("download") ||
(link.target && link.target !== "_self")
)
return;
event.preventDefault();
const url = new URL(link.href);
url.hash = window.location.hash;
if (url.href !== window.location.href) {
// This demo owns local URL state; no server data needs refetching.
// Next.js synchronizes useSearchParams with the native history API.
window.history.pushState(null, "", url);
}
}}
page={page}
pageCount={18}
showFirstLast
/>
);
}
export function PaginationLinkMode() {
return (
<Suspense
fallback={
<Pagination
aria-label="URL result pages"
page={6}
pageCount={18}
showFirstLast
/>
}
>
<LinkedPagination />
</Suspense>
);
}Narrow and RTL
Small hosts collapse to Back/Next controls while preserving logical RTL placement for the page summary.
Saved searches
Small hosts collapse to Back/Next while RTL keeps the page summary at inline-start.
Show sourceexamples/pagination/responsive-card.tsx
"use client";
import { useState } from "react";
import { Pagination } from "@dethink/components";
export function PaginationResponsiveCard() {
const [page, setPage] = useState(5);
return (
<div className="border-border bg-background mx-auto max-w-xs rounded-lg border p-4 shadow-sm">
<div className="space-y-1">
<h4 className="text-foreground text-sm font-semibold">
Saved searches
</h4>
<p className="text-muted-foreground text-sm leading-6">
Small hosts collapse to Back/Next while RTL keeps the page summary at
inline-start.
</p>
</div>
<div className="mt-4" dir="rtl">
<Pagination
aria-label="Saved search pages"
page={page}
pageCount={12}
showFirstLast
onPageChange={setPage}
/>
</div>
</div>
);
}Examples that combine components for common tasks.
Table footer
Pagination composes beside row-count copy without owning table state, page size, or fetching.
Rows 21-30 of 120
Choose the mode that matches the data source and route model.
Callback mode
Use onPageChange when the current page lives in client state, a table model, or a server action wrapper.
Link mode
Use hrefForPage for real URLs. Integrate your router to avoid document reloads. This local-state demo uses Next.js history integration; server-backed results should navigate through the router with scrolling disabled.
Unbounded mode
Omit pageCount and pass hasNextPage for cursor-backed APIs that can page forward but do not know the final page.
Responsive layout
Pagination adapts to its own container width: small hosts use a Back/Next fallback, and larger hosts restore the normal page window.
Pagination renders a nav landmark and generated controls by default, with compound anatomy available for custom composition.
| Prop | What it does | Default |
|---|---|---|
pagenumber | Current one-based page. Values are clamped to the known pageCount when pageCount is supplied. | Not set |
pageCountnumber | Known total pages for bounded pagination. Omit for cursor-style or unknown-total lists. | Not set |
hasNextPageboolean | Enables next-page controls in unbounded mode without inventing a final page. | false |
onPageChange(page: number) => void | Callback mode for client-owned state updates. Generated controls render as buttons. | Not set |
hrefForPage(page: number) => string | undefined | Link mode for route-backed pagination. Targets without URLs fall back to onPageChange or render disabled. | Not set |
compactboolean | Reduces page-window density for cards, mobile layouts, and table footers. | false |
showFirstLast / hideDisabledControlsboolean | Adds first/last controls and chooses whether impossible boundary controls are disabled or hidden. | false / false |
siblingCount / boundaryCountnumber | Controls how many pages render around the current page and at the known page boundaries. | 1 / 1 |
size"sm" | "md" | "lg" | Tokenized control size for dense tables, default pages, or larger touch targets. | "md" |
statusReactNode | false | Visible page summary. Pass false when the surrounding UI already provides the status text. | generated |
labelsPaginationLabels | Custom accessible labels for the nav landmark, page controls, boundary controls, ellipses, status, and narrow Back/Next text. | built-in English labels |
childrenReactNode | Compound anatomy escape hatch when consumers need full manual composition. | Not set |