To source

a-pager

A headless pagination element with slotted prev/next controls and CSS part styling.

The a-pager element renders numbered page links and manages pagination logic. It is intentionally unstyled — all visual design comes from the outside via CSS ::part() selectors and your own slotted controls.

Usage

<a-pager page="1" count="20" url="/results/{page}">
  <button slot="prev">← Prev</button>
  <button slot="next">Next →</button>
</a-pager>

<script>
  document.querySelector('a-pager').addEventListener('change', (e) => {
    e.currentTarget.setAttribute('page', e.detail.page);
  });
</script>

URL generation

By default, page links append ?page=N to the current URL. Provide a url template to override this:

<!-- /results/1, /results/2, ... -->
<a-pager url="/results/{page}" count="20"></a-pager>

<!-- /search?q=cats&page=3 -->
<a-pager url="/search" query="q=cats" count="20"></a-pager>

Prev / next slots

The prev and next slots accept any element. Clicks inside them are intercepted and fire a change event — no extra JavaScript needed on your buttons.

<a-pager page="3" count="10">
  <!-- anchor tags work too — navigation is prevented and replaced by the change event -->
  <a href="/page/2" slot="prev">← Previous</a>
  <a href="/page/4" slot="next">Next →</a>
</a-pager>

Styling

Page links live in the shadow DOM and are exposed via CSS parts:

PartDescription
pageEvery page number link
page activeThe currently selected page link
ellipsisThe truncation indicator
pagesThe <nav> wrapping all page links
a-pager::part(pages)       { display: flex; gap: 4px; }
a-pager::part(page)        { padding: 0.25rem 0.5rem; border: 1px solid #ccc; }
a-pager::part(page active) { background: blue; color: white; }
a-pager::part(ellipsis)    { color: #999; }

Boundary state

The at-start and at-end attributes are automatically toggled on the host element when the pager is at the first or last page. Use them to disable or hide your slotted controls:

a-pager[at-start] [slot="prev"],
a-pager[at-end]   [slot="next"] {
  opacity: 0.4;
  pointer-events: none;
}

Events

pager.addEventListener('change', (e: CustomEvent<{ page: number, url: string }>) => {
  // Update the page attribute to reflect the new page
  pager.setAttribute('page', String(e.detail.page));

  // Or navigate to the generated URL
  // window.location.href = e.detail.url;
});

Calling e.preventDefault() cancels both the browser navigation (if the page links are anchors) and the change event propagation.

Accessibility

  • The page link list is wrapped in <nav aria-label="Pagination">.
  • The active page link has aria-current="page".
  • Prev/next controls are fully slotted, so their native semantics (button role, focus behaviour) are preserved.

PagerElement

A headless pagination element. Manages page state and renders numbered page links. Accepts slotted prev/next controls — clicks on them are intercepted to fire

events so the host can update the

attribute.

Example


<a-pager page="3" count="10" url="/results/{page}">
  <button slot="prev">← Prev</button>
  <button slot="next">Next →</button>
</a-pager>

Attributes


Name Type Default value Description
count number 1

Total number of pages.

page number 1

Current page (1-indexed).

query string undefined

Additional query string params appended to every generated page URL.

url string undefined

URL template with

placeholder. Falls back to

on the current URL.

Events


Name Description
change

Fired when navigating to a page.