Component
Pagination
Range text and page links for a long list that is served one page at a time.
Plain-text source, for agents and clipboard use: /components/source/pagination.txt
When to use it
Splits a long, server-side result into pages and says which part is showing: 26–50 of 312. The page links are real links, so a page can be bookmarked, opened in a new tab and reached with the back button. Previous and Next stay in place and disable at the ends rather than disappearing, and a long run of pages collapses around the current one with gaps.
Examples
Below a table
The pagination sits after the table wrapper, which spaces it automatically. Pages near the current one are shown, with the first and last.
| Reference | Departure | Pax |
|---|---|---|
| KB-104953 | Golden Circle, 21 Sep | 6 |
| KB-104954 | South Coast, 22 Sep | 2 |
| KB-104957 | Snæfellsnes, 22 Sep | 11 |
<div class="flux-table-wrap">
<table class="flux-table">
<caption class="flux-visually-hidden">Bookings, page 2 of 13</caption>
<thead>
<tr>
<th scope="col">Reference</th>
<th scope="col">Departure</th>
<th scope="col" data-numeric>Pax</th>
</tr>
</thead>
<tbody>
<tr><th scope="row">KB-104953</th><td>Golden Circle, 21 Sep</td><td data-numeric>6</td></tr>
<tr><th scope="row">KB-104954</th><td>South Coast, 22 Sep</td><td data-numeric>2</td></tr>
<tr><th scope="row">KB-104957</th><td>Snæfellsnes, 22 Sep</td><td data-numeric>11</td></tr>
</tbody>
</table>
</div>
<nav class="flux-pagination" aria-label="Pagination">
<p class="flux-pagination__range">26–50 of 312</p>
<ul class="flux-pagination__list">
<li><a class="flux-pagination__link" href="#"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 4l-4 4 4 4" /></svg>Previous</a></li>
<li><a class="flux-pagination__link flux-pagination__page" href="#" aria-label="Page 1">1</a></li>
<li><a class="flux-pagination__link flux-pagination__page" href="#" aria-label="Page 2" aria-current="page">2</a></li>
<li><a class="flux-pagination__link flux-pagination__page" href="#" aria-label="Page 3">3</a></li>
<li><span class="flux-pagination__gap" aria-hidden="true">…</span></li>
<li><a class="flux-pagination__link flux-pagination__page" href="#" aria-label="Page 13">13</a></li>
<li><a class="flux-pagination__link" href="#">Next<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 4l4 4-4 4" /></svg></a></li>
</ul>
</nav>Previous and next only
For results served by cursor, where the total is unknown or expensive to count. On the first page, Previous is disabled rather than removed, so Next does not move.
<nav class="flux-pagination" aria-label="Pagination">
<p class="flux-pagination__range">1–25</p>
<ul class="flux-pagination__list">
<li><span class="flux-pagination__link" aria-disabled="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 4l-4 4 4 4" /></svg>Previous</span></li>
<li><a class="flux-pagination__link" href="#">Next<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 4l4 4-4 4" /></svg></a></li>
</ul>
</nav>Anatomy
| Part | Description |
|---|---|
| Navigation | A nav with aria-label="Pagination" and the flux-pagination class. |
| Range | Which records are showing and how many there are, in text-secondary with tabular figures. |
| Previous and Next | Links with an arrow and a word. At an end they become disabled spans. |
| Page | A link per page in mono. The current page is selected and carries aria-current="page". |
| Gap | An ellipsis standing for the pages left out. |
API
| Name | Kind | Description |
|---|---|---|
flux-pagination | class | On the nav. Give it aria-label="Pagination". |
flux-pagination__range | class | The range text. |
flux-pagination__list | class | On the ul of links. |
flux-pagination__link | class | On every link, and on the span that replaces a disabled Previous or Next. |
flux-pagination__page | class | Adds mono figures to a page number link. Label it "Page n". |
flux-pagination__gap | class | The ellipsis for omitted pages, with aria-hidden. |
aria-current="page" | attribute | On the current page’s link. |
aria-disabled="true" | attribute | On the span for Previous or Next at an end. |
States
| State | Treatment |
|---|---|
| Default | text-primary on no fill. |
| Hover | surface-hover fill. |
| Current | surface-selected fill, text-brand, mono bold. |
| Disabled | text-disabled, not focusable, not a link. |
Keyboard
| Keys | Action |
|---|---|
Tab | Moves through the links. Disabled ends and gaps are skipped. |
Enter | Opens the page. |
Accessibility
- Label the nav "Pagination", and each number "Page n", so a list of links reads as pages.
- The current page carries aria-current="page", so it is not conveyed by fill alone.
- Update the table caption with the page number, so the change is clear after the page loads.
- Move focus to the top of the results after a page change that does not reload the page.
Tokens
The tier-3 and tier-2 tokens this component binds to. Change the token, not the component.
- --flux-pagination-gap | -item-size | -item-text | -item-hover
- --flux-pagination-current-bg | -current-text
- --flux-pagination-range
Do and don’t
Do
- Show the first page, the last page and the pages either side of the current one.
- Keep the page in the URL so the back button returns to it.
Don’t
- Do not hide Previous or Next at an end: disable it.
- Do not use buttons for pages when a URL can identify each one.
- Do not shrink row height to fit more rows on a page.