Azalea

Pagination

Moving through a long list.

Why it exists

Eighteen pages in the suite render a pager, and between them they used four vocabularies for the same two controls — Previous/Next, Newer/Older, ‹ ›, and in Echo's case nothing at all when there was one page, so a list of nine records and a list of nine thousand looked identical.

The edges are disabled, not absent

Root and Harvest both removed the Previous link on page one, so the Next button moved sideways under the cursor between pages one and two — the one place a mis-click sends you backwards through a list you were paging forwards.

Gaps only where they save space

A pager that renders 1 … 3 4 5 has an ellipsis standing in for a single hidden page — wider than the number it replaced, and hiding nothing. pageWindow() is the part with the edges, and it lives in a .ts so it can be tested without React.

One page still says how much there is

“137 records” is the answer to a question people arrived with, and hiding it when it fits on one page hides it exactly when it is smallest and easiest to state.

In both themes

light

dark

Guidance

Use it when

  • Any list long enough to page. Pass total and perPage so the summary is a fact rather than a page number.
  • as={Link} in a Next app, so paging is a client navigation rather than a full load.
  • noun to name what is being counted — “237 runs” reads better than “237 records”.

Reach for something else when

  • Buttons and router.push. Every list in this platform keeps its state in the URL, which is what makes it linkable, back-button-able and openable in a new tab.
  • An infinite scroll on an operational list. There is no way to link to row 4,000.
  • Rendering it above the list. The pager belongs where the list runs out.

Props

PropTypeDefaultDescription
pagenumberThe current page, 1-based. Clamped into range.
pagesnumberHow many there are.
href(page: number) => stringBuilds the link. The caller owns the query string.
asElementType"a"A framework link component — Next's <Link>.
totalnumberTotal records, for the summary line.
perPagenumberWith total, turns the summary into a range: “21–40 of 137”.
nounstring"record"What is being counted. Pluralised for you.

Accessibility

A <nav> with a list of links, the current page marked aria-current="page". The ellipsis is aria-hidden — “horizontal ellipsis” read between two page numbers is noise. A disabled step is a <span>, not a link with aria-disabled: there is no destination, and a link to nowhere is still a tab stop. Below sm the step labels collapse to icons, which is why they carry an explicit aria-label.