rc-pagination
Pagination enhancer for a native <nav> holding page links or buttons, with a server-safe
page range helper.
- Package
@rcarls/rc-pagination- Element
<rc-pagination>- Native dependency
- Requires a native nav child with data-rc-page links or buttons
- State model
- Controlled or uncontrolled page
- Main events
rc-pagination-change
Installation
- npm
- Yarn
- pnpm
npm install @rcarls/rc-webcomponents@next
yarn add @rcarls/rc-webcomponents@next
pnpm add @rcarls/rc-webcomponents@next
import '@rcarls/rc-webcomponents/rc-pagination/define';
Usage
There is no WAI-ARIA pattern for pagination. The markup follows the
GOV.UK and
USWDS models: a <nav> landmark
holding a list, so screen readers announce how many items it has. Tag each control with
data-rc-page, a page number or previous, next, first, or last:
<rc-pagination total="12" page="6">
<nav>
<ul>
<li><a href="?page=5" data-rc-page="previous" rel="prev">Previous</a></li>
<li><a href="?page=1" data-rc-page="1">1</a></li>
<li aria-hidden="true">…</li>
<li><a href="?page=5" data-rc-page="5">5</a></li>
<li><a href="?page=6" data-rc-page="6" aria-current="page">6</a></li>
<li><a href="?page=7" data-rc-page="7">7</a></li>
<li aria-hidden="true">…</li>
<li><a href="?page=12" data-rc-page="12">12</a></li>
<li><a href="?page=7" data-rc-page="next" rel="next">Next</a></li>
</ul>
</nav>
</rc-pagination>
Links make the markup work with no JavaScript at all. Use buttons for paging that only happens on the client.
Building the list
paginationRange() returns the page numbers to render, with 'ellipsis' where a run of
pages is hidden. It has no DOM dependency, so a server component or route can import it
from @rcarls/rc-pagination/range without loading the element:
import { paginationRange } from '@rcarls/rc-pagination/range';
paginationRange({ page: 6, total: 12 }); // [1, 'ellipsis', 5, 6, 7, 'ellipsis', 12]
paginationRange({ page: 6, total: 12, siblings: 2, boundaries: 2 });
Live demo
Behavior
- The element keeps
aria-current="page"on the control for the current page. - It names the
<nav>"Pagination" when it has no name, and gives numbered controls the name "Page 3", which keeps the visible number in the name. Previous, next, first, and last controls keep their visible text; icon-only ones are named "Previous page" and so on. An authoredaria-labelalways wins. - Steps past either end are disabled: buttons natively, links with
aria-disabled="true"and a guard that ignores their clicks. An authored disabled state remains when a control leaves the edge. - Activating a control fires
rc-pagination-changewith{ page, previousPage }. In uncontrolled use the element moves to the requested page; withpageset, the host decides by writingpage. A numbered target beyondtotalrequests the last page, and a stale link to that target does not navigate to its out-of-range URL. rc-pagination-changeis cancelable. Canceling it also cancels the click, so a link does not navigate: use this to hand the change to a client-side router.
Accessibility
- Give each pagination landmark a distinct name when a page has more than one, such as
aria-label="Search results pages". - After a client-side page change, move focus to the start of the new results, or set
announceto have the element announce "Page 6 of 12" through a polite live region. - Hide the ellipsis items from assistive technology with
aria-hidden="true"; the page names already convey the position.
Theming
The default demo mode shows the component without a package theme. Use the shared preview controls to compare themes.
API
Properties
| Property | Markup | Type | Default | Description |
|---|---|---|---|---|
total | total | number | 1 | Number of pages. |
announce | announce | boolean | false | Announces each user change through a polite live region. |
messages | JS property only | Partial<RCPaginationMessages> | undefined | Not specified | Built-in text overrides; unset keys fall back to registered text, then English. |
page | page | number | Not specified | Current page, 1-based and clamped to `[1, total]`. Host writes are silent. |
defaultPage | default-page | number | Not specified | Initial page for uncontrolled use. |
Events
| Event | Detail type | Description |
|---|---|---|
rc-pagination-change | No detail type documented | Fired when the user activates a page control. Cancelable; canceling it also cancels the click, so a link does not navigate. |
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--rc-pagination-gap | 0.25em | Space between items. |
--rc-pagination-item-min-inline-size | Not specified | Minimum inline size of each item. Defers to the content size when unset. |