Pagination
import { Pagination, getPageItems } from '@absoluteui/components/pagination';import '@absoluteui/components/pagination/style.css';Using Angular? See Pagination for Angular.
What it does
Section titled “What it does”Navigate paged data. Pagination renders a labelled <nav> of native buttons: previous/next, optional first/last, and page numbers with ellipses. It can also show a localized result summary (“Showing 11-20 of 57”) and a native “Rows per page” <select>. User page changes are announced politely. In narrow containers the page numbers give way to “Page 3 of 10”. The pure helper getPageItems computes which pages to show, for custom renderers.
When to use
Section titled “When to use”- Tables and result lists split into pages, where users need to know and choose their position.
- Server-paged data where the total or page count is known.
When not to use
Section titled “When not to use”- Feeds consumed sequentially: use ‘Load more’ or infinite scrolling with a clear end.
- Fewer items than one page: render the list without pagination.
- Step-by-step processes: use a stepper.
Examples
Section titled “Examples”Server-paged table with rows per page
Section titled “Server-paged table with rows per page”import { Pagination, type PaginationChangeDetail } from '@absoluteui/components/pagination';
const host = document.createElement('div');document.body.append(host);const load = (page: number, pageSize: number | null): void => { host.dataset.request = `${String(page)}:${String(pageSize)}`;};const pager = Pagination.create(host, { total: 57, pageSize: 10, pageSizes: [10, 25, 50] });host.addEventListener('aui-change', (event) => { const { page, pageSize } = (event as CustomEvent<PaginationChangeDetail>).detail; load(page, pageSize);});pager.update({ total: 64 });Known page count with first/last buttons
Section titled “Known page count with first/last buttons”import { Pagination } from '@absoluteui/components/pagination';
const host = document.createElement('div');document.body.append(host);const pager = Pagination.create(host, { pageCount: 40, page: 12, showFirstLast: true, siblingCount: 2 });pager.setPage(20);Page items for a custom renderer
Section titled “Page items for a custom renderer”import { getPageItems } from '@absoluteui/components/pagination';
const items = getPageItems(5, 10);const text = items.map((item) => (item === 'ellipsis' ? '…' : String(item))).join(' ');document.title = text;import { Pagination, type PaginationChangeDetail } from '@absoluteui/components/pagination';import '@absoluteui/components/pagination/style.css';
const host = document.querySelector<HTMLElement>('#orders-pager');if (host) { const pager = Pagination.create(host, { total: 240, pageSize: 25, pageSizes: [25, 50, 100] }); host.addEventListener('aui-change', (event) => { const { page, pageSize } = (event as CustomEvent<PaginationChangeDetail>).detail; host.dataset.query = `page=${String(page)}&size=${String(pageSize)}`; pager.update({ total: 240 }); });}More usage
Section titled “More usage”import { Pagination } from '@absoluteui/components/pagination';
const host = document.createElement('div');document.body.append(host);Pagination.create(host, { total: 57, pageSize: 10, page: 2 });Anatomy
Section titled “Anatomy”<div class="aui-pagination"> (consumer host, size container) <nav class="aui-pagination__nav" aria-label="Pagination"> <p class="aui-pagination__summary">Showing 11-20 of 57</p> (total known) <div class="aui-pagination__controls"> <button class="aui-pagination__button aui-pagination__first" aria-label="First page"> (showFirstLast) <button class="aui-pagination__button aui-pagination__previous" aria-label="Previous page"> <ul class="aui-pagination__pages"> <li class="aui-pagination__item"><button class="aui-pagination__page" aria-label="Page 1">1</button></li> <li class="aui-pagination__item aui-pagination__ellipsis" aria-hidden="true">...</li> <li class="aui-pagination__item"><button class="aui-pagination__page" aria-current="page" aria-label="Page 3">3</button></li> </ul> <span class="aui-pagination__compact">Page 3 of 10</span> (narrow containers only) <button class="aui-pagination__button aui-pagination__next" aria-label="Next page"> <button class="aui-pagination__button aui-pagination__last" aria-label="Last page"> (showFirstLast) </div> <div class="aui-pagination__size"> (pageSizes) <label class="aui-pagination__size-label" for>Rows per page</label> <select class="aui-pagination__size-select"> </div> </nav></div>API reference
Section titled “API reference”Factory
Section titled “Factory”Pagination.create(host: HTMLElement, options: PaginationOptions): PaginationGlobal configuration key: pagination (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
page |
number |
1 |
Current page, 1-based; clamped to 1..pageCount. |
pageCount |
number |
Number of pages. Provide either pageCount or total. | |
total |
number |
Total items; the page count is derived from pageSize. Enables the summary. | |
pageSize |
number |
Items per page. Required with total unless pageSizes is set (then defaults to its first entry). | |
pageSizes |
readonly number[] |
Render a native ‘Rows per page’ select with these sizes. | |
label |
string |
"Pagination (localized)" |
Accessible name of the <nav>. |
icons |
Partial<{ previous: IconRef; next: IconRef; first: IconRef; last: IconRef }> |
Icon slot overrides. | |
siblingCount |
number |
1 |
Pages shown on each side of the current page (0 to 10). Globally configurable. |
boundaryCount |
number |
1 |
Pages always shown at the start and end (0 to 10). Globally configurable. |
showFirstLast |
boolean |
false |
Render first/last page buttons. Globally configurable. |
showSummary |
boolean |
true |
Show ‘Showing 11-20 of 57’ when total is known. Globally configurable. |
locale |
string |
"en-US" |
Message and number-formatting locale. Globally configurable. Inherited from common configuration. |
direction |
'ltr' | 'rtl' |
"ltr" |
rtl mirrors the direction icons. Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
Consumer host; its children are owned by the component. |
nav |
HTMLElement |
The <nav> landmark. |
page |
number |
Current page (1 when there are no pages). |
pageCount |
number |
Number of pages (given or derived from total and pageSize). |
pageSize |
number | null |
Items per page, or null when only pageCount is known. |
options |
Readonly<PaginationOptions> |
Current instance options. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
setPage(page: number): void |
Go to a page programmatically (clamped; no events, no announcement). |
update(options: Partial<PaginationOptions>): void |
Merge and apply options. Passing pageCount drops total and vice versa. |
destroy(): void |
Remove rendering, listeners, and subscriptions. |
getPageItems(page: number, pageCount: number, siblingCount?: number, boundaryCount?: number): (number | 'ellipsis')[] |
Pure helper (module export): the page numbers and ellipses to render. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-change |
{ page: number; pageSize: number | null } |
Yes | No | The user changed the page or the page size. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-pagination |
Host (size container). |
aui-pagination--rtl |
Configured rtl direction. |
aui-pagination__nav |
The <nav> landmark. |
aui-pagination__summary |
Result summary. |
aui-pagination__controls |
Buttons row. |
aui-pagination__button |
Any pagination button. |
aui-pagination__first | __previous | __next | __last |
Direction buttons. |
aui-pagination__pages |
List of page items. |
aui-pagination__item |
A page item <li>. |
aui-pagination__page |
A page button; [aria-current=page] for the current one. |
aui-pagination__ellipsis |
Decorative gap marker. |
aui-pagination__compact |
‘Page 3 of 10’ text shown in narrow containers. |
aui-pagination__size | __size-label | __size-select |
Rows-per-page field. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
previous |
chevron-left |
next |
chevron-right |
first |
chevrons-left |
last |
chevrons-right |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border-strong | --aui-color-focus-ring | --aui-color-hover | --aui-color-primary | --aui-color-selected | --aui-color-selected-text | --aui-color-surface | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-control-height-md | --aui-control-padding-x | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-weight-semibold | --aui-icon-size-sm | --aui-line-height-normal | --aui-radius-md | --aui-space-1 | --aui-space-2 | --aui-space-3 | --aui-touch-target-min
TypeScript definitions
Section titled “TypeScript definitions”type PageItem = number | 'ellipsis';function getPageItems(page: number, pageCount: number, siblingCount?: number, boundaryCount?: number): PageItem[];interface PaginationIcons { previous: IconRef; next: IconRef; first: IconRef; last: IconRef }interface PaginationChangeDetail { page: number; pageSize: number | null }Accessibility
Section titled “Accessibility”Pattern: Navigation landmark of native buttons (no dedicated APG pattern), following common accessible pagination practice: named buttons, aria-current on the current page, disabled bounds, and announced changes.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Tab / Shift+Tab | Any | Moves between enabled buttons and the rows-per-page select (native tab order). |
| Enter / Space | Button focused | Activates the button (changes the page). |
| Arrow keys | Rows-per-page select focused | Native select behavior. |
| Element | Role |
|---|---|
| <nav> | navigation (native landmark) |
| <ul> | list (native) of page items |
| <button> | button (native) |
| <select> | combobox (native select) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-label |
<nav> | label option or localized ‘Pagination’ |
aria-label |
page button | Localized ‘Page 3’ with a locale-formatted number |
aria-current |
current page button | page |
aria-label |
first/previous/next/last | Localized ‘First page’, ‘Previous page’, ‘Next page’, ‘Last page’ |
aria-hidden |
ellipsis items, icons | true (decorative) |
disabled |
previous/next/first/last | Native disabled at the bounds |
After a page change the page buttons are re-rendered; focus stays on the same control (for example Next, or the page number clicked). When that control becomes disabled or hidden, focus moves to the current page button, then to previous/next.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”| Criterion | Level | Note |
|---|---|---|
| 1.3.1 Info and Relationships | A | |
| 1.4.1 Use of Color | A | |
| 1.4.10 Reflow | AA | |
| 2.1.1 Keyboard | A | |
| 2.4.3 Focus Order | A | |
| 2.4.7 Focus Visible | AA | |
| 4.1.2 Name, Role, Value | A | |
| 4.1.3 Status Messages | AA |
Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- User page changes are announced through the shared polite live region: the summary (‘Showing 11-20 of 57’) when the total is known, otherwise ‘Page 3 of 10’. Programmatic changes are not announced.
- The rows-per-page select has a visible native label.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver) is pending.
Behavior
Section titled “Behavior”States
Section titled “States”default, hover, focus-visible, current page, disabled (at the bounds), compact (narrow container), empty (no pages).
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| page n | page button, previous, next, first, or last | new page; aui-change; announcement |
| page n, size s | rows-per-page select | size s′; page recomputed so the first item of the old page stays visible; aui-change |
| any | setPage(n) / update({ page }) |
page clamped to 1..pageCount; no event |
| page n | update({ total }) makes the count smaller |
page clamped; no event |
Accessibility notes
Section titled “Accessibility notes”- User page changes are announced through the shared polite live region: the summary when the total is known, otherwise “Page 3 of 10”. Programmatic changes are silent.
- Focus stays on the activated control across re-renders. If that control becomes disabled (for example Previous on page 1), focus moves to the current page button.
- The current page is shown by fill, border, and weight, not by color alone.
- Manual screen-reader verification is pending (see Known limitations).
Responsive behavior
Section titled “Responsive behavior”The host is a size container. Below 30rem of inline space, page numbers are hidden and “Page 3 of 10” is shown between previous and next. Buttons keep the minimum touch-target size. Summary, controls, and the size select wrap as needed.
Right-to-left
Section titled “Right-to-left”Layout follows the document direction. Chevron icons are mirrored when direction is 'rtl' or when the element is in an rtl context (:dir(rtl)), so “previous” always points against the reading direction.
Theming
Section titled “Theming”Colors come from role tokens only. Verified in the light, dark, and high-contrast themes. In forced-colors mode the current page uses Highlight/HighlightText and disabled buttons use GrayText.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { pagination: { siblingCount: 2, showFirstLast: true } } });Changes apply to existing instances immediately.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All options are dynamic.
icons.previous (default chevron-left), icons.next (chevron-right), icons.first (chevrons-left), and icons.last (chevrons-right).
Security
Section titled “Security”All text uses textContent; nothing is parsed as HTML. CSP-safe.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry. The component never fetches data; load pages on aui-change.
Performance
Section titled “Performance”Two listeners (a delegated click on the controls, and change on the select) plus one configuration subscription per instance. Rendered page items are bounded by siblingCount and boundaryCount, not by the page count. Budget: under 1 ms for Pagination.create with 10,000 pages.
Supported data scale
Section titled “Supported data scale”Any page count up to Number.MAX_SAFE_INTEGER. getPageItems is tested exhaustively for page counts 0 to 30 across seven sibling/boundary combinations.
Edge cases
Section titled “Edge cases”total: 0gives zero pages: no page buttons, previous and next disabled, and the summary “No results”.- One page: a single current page button; previous and next disabled.
pageoutside 1..pageCount is clamped.- Changing rows per page from 10 to 25 on page 4 (items 31-40) goes to page 2 (items 26-50).
boundaryCount: 0does not always show the first and last pages; combine it withshowFirstLast.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
PAGINATION_OPTIONS |
configuration | Neither or both of pageCount/total; negative or non-integer counts; total without pageSize/pageSizes; a pageSize not in pageSizes; empty pageSizes; an empty label; a non-integer page. |
PAGINATION_ITEMS |
configuration | getPageItems called with non-integer or negative arguments. |
CFG_INVALID_VALUE |
configuration | Invalid siblingCount, boundaryCount, showFirstLast, showSummary, locale, or direction. |
A failed construction leaves no rendering, listeners, or subscriptions behind.
Known limitations
Section titled “Known limitations”- No “go to page” input.
- The compact breakpoint (30rem container width) is fixed.
- Screen-reader behavior has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Unsupported scenarios
Section titled “Unsupported scenarios”- Cursor-based pagination without a known page count.
- Page items as links (
href).