molecule · stable · since 2026-09
Pagination
Purpose
The passage from one page of a list to the next: a list of links in a named landmark, each saying its destination out of context, the bounds gone rather than disabled, the truncation honest, the count announced.
When to use, when not
Use it under any list served in pages. Not for steps (a wizard), not for tabs.
Anatomy
- The count, a status region: “Résultats 11 à 20 sur 38 utilisateurs”.
- The landmark, named.
- The links: previous, the numbers with the gaps, next.
Props
| Name | Type | Default | What it does |
|---|---|---|---|
page | number | The current page, from 1. | |
pages | number | The number of pages. | |
label | string | The landmark's name: "Pagination des utilisateurs". Two paginations on one screen need two names. | |
href | (page: number) => string | The address of a page. | |
onnavigate? | (page: number, event: MouseEvent) => void | For a list updated in place: called with the page and the click, which the page prevents. | |
total? | number | The number of rows in all, for the count. | |
perPage? | number | The rows per page, for the count. | |
rowsName? | string | 'résultats' | What is counted, in the plural: "utilisateurs". |
class? | string | '' | Layout classes only. |
States
Seven pages, forty-two pages, and with the count.
counted
With the total and the rows per page, the count is a status region present from the first render.
Light
Résultats 11 à 20 sur 38 utilisateurs
Dark
Résultats 11 à 20 sur 38 utilisateurs
320 px, light
Résultats 11 à 20 sur 38 utilisateurs
320 px, dark
Résultats 11 à 20 sur 38 utilisateurs
216 px, light
Résultats 11 à 20 sur 38 utilisateurs
Forced colours, captured

long
Forty-two pages: the first, the last, the current one with its neighbours, and an ellipsis that is not a link where it skips.
Light
Dark
320 px, light
320 px, dark
216 px, light
Forced colours, captured

short
Seven pages or fewer: every number shows. Out of context each link says "Page 4"; the current one carries aria-current.
Light
Dark
320 px, light
320 px, dark
216 px, light
Forced colours, captured

Accessibility contract
- Role and name:
navigationnamed bylabel; a list of links; the current page carriesaria-current="page". The gaps are hidden and are not links. - Keyboard, focus: ordinary links. When a list updates in place and the activated link disappears, the focus is put on the current page’s link.
- Live regions: the count,
role="status", present even with one page.
Content rules
French. The label names what is paginated: “Pagination des utilisateurs”. rowsName is the plural noun of the rows.
Do and don’t
- Do give two paginations on one screen two labels.
- Do let the links navigate; intercept them only for a list that updates in place, and then prevent the default in
onnavigate. - Do not write the first page in the address; the component only makes the links, but the page’s
hrefshould droppage=1.
Examples
<Pagination page={state.page} pages={state.pages} total={state.total} perPage={10} rowsName="utilisateurs" label="Pagination des utilisateurs" href={(p) => link(p)} /> Surfaces
- App: the users list and the two lists of registrations, with the address of a page from the app’s helper.
Related
Table, DataTable, Link.
Decisions
- 2026-09-24: links only, and the bounds removed rather than greyed, as both sources argue; the truncation is the app’s, which had learnt on the registrations that a sliding window hides the ends.
- 2026-09-27: the focus is caught only on a change of page, never at mount. On a fresh load the focus is on the body too, and the list took it and scrolled the admin pages down to itself before anyone had pressed a key.
Criteria held by construction
- 12.6, Les zones de regroupement de contenus présentes dans plusieurs pages web (zones d'en-tête, de navigation principale, de contenu principal, de pied de page et de moteur de recherche) peuvent-elles être atteintes ou évitées ?
A navigation landmark with its own name, so two paginations on one screen are told apart in the list of regions. - 6.1, Chaque lien est-il explicite ?
Every link says its destination out of context: 'Page 4', 'Page suivante'; a bare number would not. - 7.5, Dans chaque page web, les messages de statut sont-ils correctement restitués par les technologies d'assistance ?
The count is a status region present from the first render, so a list updated in place is announced. - 3.1, Dans chaque page web, l'information ne doit pas être donnée uniquement par la couleur. Cette règle est-elle respectée ?
The current page is told by aria-current and the strong line under it, not by colour alone.
Tokens it reads
- Colour:
--rl-action,--rl-hover,--rl-ink,--rl-ink-soft,--rl-line-control,--rl-line-strong - Typography:
--rl-weight-bold,--rl-text-sm - Spacing:
--rl-space-1,--rl-space-2,--rl-space-3 - Layout:
--rl-radius,--rl-border