Skip to content
Dethink Components

ComponentsPagination

Pagination

Let users move between pages of results.

On this page

Install component source from the public registry, or use the local workspace package. Follow the setup guide first. The npm package is not published yet.

View registry files

Implemented with React and browser APIs, without an additional behavior or rendering library.

Shared foundation: React, clsx for conditional classes, tailwind-merge for resolving utility-class conflicts. Styles use Tailwind CSS and Dethink CSS variables.

Based on this component’s source and registry composition. Libraries used only in showcase examples are excluded.

Import the component into your page or component file.

Usage
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
examples/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}
    />
  );
}

Real page URLs with in-place navigation: the selected page follows the URL, browser Back/Forward works, and changing pages preserves your scroll position.

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
examples/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.

Pagination composes beside row-count copy without owning table state, page size, or fetching.

InvoiceAmountStatus
INV-1048Acme EU$12,420Paid
INV-1049Northstar$8,115Pending
INV-1050Rivet Labs$4,680Paid

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.

Pagination props
PropWhat it doesDefault
pagenumberCurrent one-based page. Values are clamped to the known pageCount when pageCount is supplied.Not set
pageCountnumberKnown total pages for bounded pagination. Omit for cursor-style or unknown-total lists.Not set
hasNextPagebooleanEnables next-page controls in unbounded mode without inventing a final page.false
onPageChange(page: number) => voidCallback mode for client-owned state updates. Generated controls render as buttons.Not set
hrefForPage(page: number) => string | undefinedLink mode for route-backed pagination. Targets without URLs fall back to onPageChange or render disabled.Not set
compactbooleanReduces page-window density for cards, mobile layouts, and table footers.false
showFirstLast / hideDisabledControlsbooleanAdds first/last controls and chooses whether impossible boundary controls are disabled or hidden.false / false
siblingCount / boundaryCountnumberControls 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 | falseVisible page summary. Pass false when the surrounding UI already provides the status text.generated
labelsPaginationLabelsCustom accessible labels for the nav landmark, page controls, boundary controls, ellipses, status, and narrow Back/Next text.built-in English labels
childrenReactNodeCompound anatomy escape hatch when consumers need full manual composition.Not set