Pagination

Molecule

Numbered page-navigation control for long lists and tables. Mirrors Figma node 141-8644 (light) + 5941-919 (dark) 1:1. Pure composition over Button — the active page reuses .btn.btn-primary, inactive pages + Previous / Next reuse .btn.btn-ghost. The pagination's size class (lg / md default / sm) overrides the button defaults so all cells track a uniform 40 / 36 / 32 px row height with Body 1 / Body 2 / Caption 1 Semi Bold typography. Page-number cells are square (width = height) via the .btn-square modifier; the .pagination-ellipsis separator occupies the same cell but is non-interactive. No new tokens — every colour value flows through the existing Button system.

When to use

✅ Do
  • Use when displaying large data sets that are split across pages (tables, lists)
  • Always show Previous and Next buttons alongside page numbers
  • Use ellipsis (.pagination-ellipsis) to truncate long page ranges
  • Highlight the current page with the Primary button variant
❌ Don't
  • Use for fewer than 3 pages — show all items or use infinite scroll instead
  • Show all page numbers without truncation for large page counts
  • Use for sequential step navigation — use a Stepper component instead
  • Disable Previous/Next without communicating the boundary to users

DigiLawyer Patterns

No specific DigiLawyer patterns documented yet — to be added.

Anatomy

Pagination composes entirely with Button — no new tokens. Page cells use .btn-square for equal width/height.

  1. 1Nav wrapper.pagination. Flex row with role="navigation".
  2. 2Prev / Next.btn.btn-ghost.btn-square. Arrow icon buttons at each end.
  3. 3Page button.btn.btn-ghost.btn-square. Inactive page number.
  4. 4Active page.btn.btn-primary.btn-square. Current page in Primary.
  5. 5Ellipsis.pagination-ellipsis. Non-interactive gap indicator.

Default

A bare .pagination at the default md density. The current page is marked with aria-current="page" (drives the .btn-primary visual). Use <nav role="navigation"> + aria-label="Pagination" so assistive tech announces the control.

Sizes

Three densities map 1:1 to Figma's symbol sizes. .pagination-lg is 40 px tall with Body 1 (16/24) Semi Bold; default .pagination (md) is 36 px tall with Body 2 (14/24); .pagination-sm is 32 px tall with Caption 1 (12/16). Chevron icons step 16 / 14 / 12 px to match. The cascade is owned by the .pagination[-size] class, not the inner buttons — drop the .btn-{size} suffix on each button and let Pagination drive the row.

Large
Medium
Small

States

Per-button states cascade from Button. Default renders the ghost / primary tone. Hover fades the ghost cell's background (--btn-ghost-bg-hover) and deepens the primary cell. Active page uses the primary fill and carries aria-current="page". Disabled — the natural state of Previous on page 1 and Next on the last page — uses the native disabled attribute and inherits --btn-ghost-text-disabled. The ellipsis is non-interactive and has no states.

Composition

Pagination usually lives at the foot of a Table or a paged list. Two common framings: icon-only Prev / Next for tight surfaces (drop the "Previous" / "Next" labels and let the chevron carry the affordance), and a truncated middle for very long ranges (show first 2 pages + ellipsis + current ± 1 + ellipsis + last 2 pages). Pagination doesn't ship a built-in renderer for the ellipsis logic — wire it on the caller side so the consumer controls the page-window strategy.

Icon-only Prev / Next
Inside a Table footer
NameEmailRole
Adesh Singhadesh@example.comOwner
Jane Doejane@example.comEditor
Mark Patelmark@example.comViewer

Full matrix

3 sizes × 4 page-position states (page 1, mid-range, second-to-last, last). Toggle the theme switch in the global header to see every cell under dark tokens — Button-primary flips white-on-dark → dark-on-white; Button-ghost inverts text colour; disabled --btn-ghost-text-disabled flips light grey → dark grey.

Responsive

Add .pagination-auto alongside .pagination to auto-switch to sm density (32 px / Caption 1) on screens narrower than 744 px. At wider breakpoints the size tracks whatever .pagination[-lg|-sm] modifier you set.

Frame above simulates a 390 px mobile viewport — items shrink to 32 px height.

HTML
<nav class="pagination pagination-auto" aria-label="Pagination"></nav>

Accessibility

Attribute / BehaviourValueNotes
Nav wrapperrole="navigation" + aria-label="Pagination"Identifies the pagination as a landmark navigation region
Current pagearia-current="page"Set on the active page button so screen readers announce "current page"
Disabled Prev/Nextaria-disabled="true" + disabledCommunicate the boundary when on page 1 (disable Prev) or last page (disable Next)
Ellipsisaria-hidden="true"The ellipsis is decorative — screen readers don't need to announce it
KeyboardTab + EnterAll page buttons are in the natural tab order

API

Class / attrOnDescription
.pagination<nav role="navigation" aria-label>Wrapper. Inline-flex with --spacing-xs gap between cells. Default density (md) — 36 px tall, Body 2 (14/24) Semi Bold. Cascades size + icon scaling to all inner .btns.
.pagination-lg.paginationLarge — 40 px tall, Body 1 (16/24) Semi Bold, 16 × 16 chevron icons.
.pagination-sm.paginationSmall — 32 px tall, Caption 1 (12/16) Semi Bold, 12 × 12 chevron icons.
.btn.btn-ghost<button> inside .paginationInactive page numbers + Previous / Next. Composes with the canonical Button ghost variant.
.btn.btn-primary<button> inside .paginationThe active page cell. Pair with aria-current="page" for screen readers.
.btn-square.btnSquare hit area — drops horizontal padding and clamps min-width to the row height (40 / 36 / 32 px per pagination size). Use on every page-number cell.
.pagination-ellipsis<span aria-hidden="true">Non-interactive separator that occupies the same cell as a page button. Use to skip a long mid-range without leaving a gap. No hover / focus surface.
disabled.btnNative disabled — apply to Previous on page 1 and Next on the last page. Inherits --btn-ghost-text-disabled.
aria-current="page".btnMarks the active page cell. Required for assistive tech; the visual swap is driven by .btn-primary.
aria-label="Pagination"<nav>Recommended on the wrapper so assistive tech announces the landmark.