Pagination
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
- 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
- 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.
- 1Nav wrapper —
.pagination. Flex row withrole="navigation". - 2Prev / Next —
.btn.btn-ghost.btn-square. Arrow icon buttons at each end. - 3Page button —
.btn.btn-ghost.btn-square. Inactive page number. - 4Active page —
.btn.btn-primary.btn-square. Current page in Primary. - 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.
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.
| Name | Role | |
|---|---|---|
| Adesh Singh | adesh@example.com | Owner |
| Jane Doe | jane@example.com | Editor |
| Mark Patel | mark@example.com | Viewer |
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.
<nav class="pagination pagination-auto" aria-label="Pagination">…</nav>
Accessibility
| Attribute / Behaviour | Value | Notes |
|---|---|---|
| Nav wrapper | role="navigation" + aria-label="Pagination" | Identifies the pagination as a landmark navigation region |
| Current page | aria-current="page" | Set on the active page button so screen readers announce "current page" |
| Disabled Prev/Next | aria-disabled="true" + disabled | Communicate the boundary when on page 1 (disable Prev) or last page (disable Next) |
| Ellipsis | aria-hidden="true" | The ellipsis is decorative — screen readers don't need to announce it |
| Keyboard | Tab + Enter | All page buttons are in the natural tab order |
API
| Class / attr | On | Description |
|---|---|---|
| .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 | .pagination | Large — 40 px tall, Body 1 (16/24) Semi Bold, 16 × 16 chevron icons. |
| .pagination-sm | .pagination | Small — 32 px tall, Caption 1 (12/16) Semi Bold, 12 × 12 chevron icons. |
| .btn.btn-ghost | <button> inside .pagination | Inactive page numbers + Previous / Next. Composes with the canonical Button ghost variant. |
| .btn.btn-primary | <button> inside .pagination | The active page cell. Pair with aria-current="page" for screen readers. |
| .btn-square | .btn | Square 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 | .btn | Native disabled — apply to Previous on page 1 and Next on the last page. Inherits --btn-ghost-text-disabled. |
| aria-current="page" | .btn | Marks 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. |