Skip to content

Overlays & navigation

Pagination

Pagination moves through pages of results. Pagination is the pager itself: previous and next, page numbers with ellipses that keep a constant width, and a compact form for phones. PaginationBar is the full table footer, adding “Showing 1–10 of 128” and a rows-per-page select. Use callbacks for client-side paging or getHref for real, shareable links.

On this page

Showing 1–10 of 128 invoices

Usage

components/ui/pagination.tsx
import { Pagination, PaginationBar } from "@/components/ui/pagination"; <Pagination page={page} pageCount={24} onPageChange={setPage} />

Examples

Results footer

Changing the page size resets to page 1. The summary is a polite live region, so the new range is announced.

Showing 1–10 of 128 invoices

Page numbers

The first and last pages are always shown. siblings sets how many pages appear on each side of the current one; the list keeps the same length while paging, so buttons don't jump under the pointer.

Compact

Previous, next and “Page 3 of 12”: for phones, narrow cards and infinite lists.

getHref renders Next.js links instead of buttons (in your app, return something like /invoices?page=3), so every page has a URL, works in a static export and can be opened in a new tab.

Props

Pagination

  • pagerequirednumberdefault: —Current page, starting at 1.
  • pageCountrequirednumberdefault: —Total number of pages.
  • onPageChange(page: number) => voiddefault: —Called with the new page (button mode).
  • getHref(page: number) => stringdefault: —Render links instead of buttons.
  • siblingsnumberdefault: 1Pages shown on each side of the current one.
  • compactbooleandefault: falseOnly previous / next and “Page x of y”.

PaginationBar

  • page / pageSize / totalrequirednumberdefault: —Current page, rows per page and the total number of rows.
  • onPageChangerequired(page: number) => voiddefault: —Called with the new page.
  • onPageSizeChange(size: number) => voiddefault: —Shows the rows-per-page select when set.
  • pageSizeOptionsnumber[]default: [10, 25, 50, 100]Choices in the select.
  • itemLabelstringdefault: "results"Noun after the count, e.g. “invoices”.

pageRange()

  • pageRange(page, count, siblings?) => (number | "…")[]default: —The page list on its own, for building a custom pager.

Accessibility

  • Wrapped in <nav aria-label="Pagination">. The current page has aria-current="page".
  • Every control has a clear name: “Previous page”, “Next page”, “Page 7”. On phones the Previous / Next text is hidden but the names stay.
  • Previous and Next are disabled (not removed) at the ends, so the layout stays put.
  • Ellipses are hidden from screen readers. The “Showing …” summary updates politely after each change.

Suggested