Pagination

Moves between pages of results, with previous and next controls and a compact page range.

StableSource

Import

tsx
import { Pagination, getPageRange } from "@merid/react";

Anatomy

Pagination is a single component. It renders:

  • a <nav> landmark with a list inside,
  • a previous control and a next control (icon buttons with labels),
  • page buttons — the first, the last, siblingCount pages each side of the current one,
  • an ellipsis wherever two or more pages are skipped.

Examples

Controlled

Pass page and onPageChange when the page lives in your state or the URL.

Showing results 1–20

More siblings

siblingCount sets how many pages show on each side of the current one.

With getHref, each other page renders as an <a> so results are crawlable and open in a new tab. The current page renders as plain text (not a link to itself) with aria-current="page". Disabled previous/next controls stay buttons.

For client-side routing, add renderLink. It receives every prop of the link (href, className, aria-label, aria-current, onClick, children, …) plus the target page:

tsx
import NextLink from "next/link";

<Pagination
  pageCount={12}
  page={page}
  getHref={(p) => `/invoices?page=${p}`}
  renderLink={({ page, ...props }) => <NextLink {...props} />}
/>

Custom layouts with getPageRange

getPageRange(page, pageCount, siblings = 1) returns the same range the component uses, as an array of page numbers and "ellipsis-start" / "ellipsis-end" markers.

tsx
getPageRange(5, 12); // [1, "ellipsis-start", 4, 5, 6, "ellipsis-end", 12]

API reference

Pagination

Renders <nav> and accepts its HTML attributes except onChange.

PropTypeDefaultDescription
pageCountRequirednumber–Total number of pages (≥ 1).
pagenumber–Controlled current page, 1-based.
defaultPagenumber1Initial page when uncontrolled.
onPageChange(page: number) => void–Called with the requested page.
siblingCountnumber1Pages shown on each side of the current one.
getHref(page: number) => string–When given, pages render as links with this href; the current page renders as text.
renderLink(props: PaginationLinkProps) => ReactNode–With getHref, renders each link yourself (e.g. a router link). Spread every prop except `page` onto an element that renders an `<a>`.
aria-labelstring"Pagination"Accessible name of the landmark.
previousLabelstring"Previous page"Label of the previous button.
nextLabelstring"Next page"Label of the next button.
pageLabel(page: number) => string(p) => `Page ${p}`Builds the accessible label for a page button.
refRef<HTMLElement>–Forwarded ref to the nav element.

getPageRange

PropTypeDefaultDescription
pageRequirednumber–Current page, clamped to 1…pageCount.
pageCountRequirednumber–Total pages.
siblingsnumber1Pages on each side of the current one.

Returns PageRangeItem[], where PageRangeItem = number | "ellipsis-start" | "ellipsis-end".

Styling

  • .mrd-pagination / .mrd-pagination__list — nav root and the flex list.
  • .mrd-pagination__page — a page button, link, or (current page in link mode) text: --mrd-icon-button-md square, --mrd-radius-md.
  • .mrd-pagination__page[aria-current="page"] (also data-state="active") — current page: --mrd-accent-soft fill, --mrd-accent-strong text.
  • .mrd-pagination__control with data-direction="previous" or "next" — chevron controls; :disabled uses --mrd-placeholder.
  • .mrd-pagination__ellipsis — the … gap, hidden from assistive tech.

On coarse pointers controls grow to --mrd-icon-button-lg. Reduced motion removes the press scale.

Accessibility

There is no dedicated APG pattern for pagination; it follows the landmark regions guidance for a named navigation region.

  • The list sits inside a nav named "Pagination". Name it more specifically (for example "Search results pages") when a page has several.
  • Every page control has an accessible label from pageLabel; the current page has aria-current="page".
  • Previous and next are disabled, not hidden, at the ends, so the layout does not shift.
  • Ellipses are aria-hidden.
KeyAction
TabMoves focus to the next control.
EnterActivates the focused page or control.
SpaceActivates the focused button (button mode).

Guidelines

Do

Show a result count near the pagination and scroll the list back to the top when the page changes.

Avoid

Use pagination for a handful of items or for steps in a flow. Use a Stepper for sequential tasks.

Do

Use getHref when pages are real URLs, so people can share and bookmark them.

Avoid

Change the page size silently between pages.