Pagination
A <nav> around an ordered list of real links. Server-renderable at every tier.
Example (a11y tier)
Import
import Pagination from 'abaabil/pagination' // structure onlyimport Pagination from 'abaabil/pagination/styled' // + CSSimport Pagination from 'abaabil/pagination/a11y' // + names and aria-currentLinks, not buttons
Each page is a URL. Rendering it as a link means it can be opened in a new tab, bookmarked, shared and reached by a crawler; rendering it as a button takes all of that away and gives nothing back. The only thing a button buys is not having to build the URL, which the href prop does for you.
The gap is drawn, and only when it earns its place
The ellipsis is a CSS pseudo-element, not text, so it never reaches the accessibility tree. A screen reader reading “1 ellipsis 5 6 7 ellipsis 20” is reading punctuation aloud.
It also only appears when it stands in for two or more pages. A gap replacing a single number takes the same room and says less, so that number is drawn instead. Getting this wrong is easy and invisible: an early version put an ellipsis where page 2 should have been at page 4 of 12, and it was a test rather than a screenshot that caught it.
Names, not digits
A link whose entire content is “7” is announced as “7”. In a list of links that is meaningless, so every number is named “Page 7” while still drawing only the digit. Previous and Next say where they go.
All four labels are props, because a paginator with hardcoded English is not translatable, and this is the component where that shows up first.
Props
| Prop | Type | Default | Tier | Description |
|---|---|---|---|---|
page | number | — | all | Current page, 1-based. |
pageCount | number | — | all | Total pages. |
href | (page) => string | — | all | Builds each page's URL. |
siblings | number | 1 | all | Pages shown either side of the current one. |
label | string | 'Pagination' | a11y | Names the <nav>. |
pageLabel | (n) => string | `Page ${n}` | a11y | Names each number. |
previousLabel | string | 'Previous page' | a11y | — |
nextLabel | string | 'Next page' | a11y | — |
At either end, Previous and Next are not links at all, so nothing dead stays in the tab order.