block

Pagination

A composed block for navigating paginated data. Combines first/previous/next/last navigation buttons with a page picker select and an optional items-per-page selector. Navigation buttons default to icon-only with visually hidden labels for accessibility.

Built on the framework-agnostic @pindoba/core-pagination (connectPagination) headless core and available for both Svelte and Astro. It also powers the Table footer. The Astro component is interactive out of the box (it self-syncs and emits a pindoba:change event); for full client control call mountPagination.

Default

1 - 10 / 120
/ 12

On page 1

---
import Pagination from "../pagination.astro";
---

<div data-demo="pagination-default">
  <Pagination itemsTotal={120} itemsPerPage={10} />
  <p data-pagination-readout aria-live="polite" style="margin-top: 0.75rem;">
    On page 1
  </p>
</div>

<script>
  // The component is interactive out of the box (it self-syncs disabled state,
  // the summary, and the selects). It also emits `pindoba:change` so consumers
  // can react — here we reflect the current page into a readout.
  function boot() {
    const root = document.querySelector<HTMLElement>(
      '[data-demo="pagination-default"]',
    );
    if (!root) return;
    const readout = root.querySelector<HTMLElement>(
      "[data-pagination-readout]",
    );
    root.addEventListener("pindoba:change", (event) => {
      const detail = (event as CustomEvent).detail as {
        page: number;
        itemsPerPage: number;
      };
      if (readout) {
        readout.textContent = `On page ${detail.page + 1} (showing ${detail.itemsPerPage} per page)`;
      }
    });
  }

  boot();
  document.addEventListener("astro:page-load", boot);
</script>

Visible Labels

Show text labels alongside icons on the navigation buttons by setting visuallyHidden: false on any label key. This is useful when space allows or when a more explicit UI is preferred.

1 - 10 / 100
/ 10
---
import Pagination from "../pagination.astro";

// Unhiding a label turns the icon-only step buttons into labelled ones.
const labels = {
  first: { visuallyHidden: false },
  previous: { visuallyHidden: false },
  next: { visuallyHidden: false },
  last: { visuallyHidden: false },
};
---

<Pagination itemsTotal={100} itemsPerPage={10} labels={labels} />
props · 17 shown · 17 total
buttonEmphasis
"primary""secondary""ghost"
default "secondary"

Emphasis for the navigation buttons.

id
string

Stable id used to associate `<label>`s with their `<select>`s.

itemsPerPage
number
default 10

Items shown per page. The items-per-page selector offers `pageSizeOptions` filtered to those ≤ `itemsTotal`. Supports two-way binding.

itemsTotal
number

Total item count across all pages. Drives the "X – Y / Z" summary and, when `pageCount` is omitted, the derived page count + items-per-page capping.

labels
PaginationLabels

Override the text or visibility for each navigation label. Each key accepts `text` to change the copy and `visuallyHidden` to toggle screen-reader-only vs visible. Navigation buttons default to `visuallyHidden: true` (icon-only with `aria-label`).

onChangeItemsPerPage svelte
(itemsPerPage: number) => void

Fires with the new page size when the items-per-page select changes.

onChangePage svelte
(page: number, oldPage: number) => void

Fires with the new page (and the previous one) whenever navigation or the page select commits a change.

onFirst svelte
() => void

Fires after the first-page button commits its page change.

onLast svelte
() => void

Fires after the last-page button commits its page change.

onNext svelte
() => void

Fires after the next button commits its page change.

onPrevious svelte
() => void

Fires after the previous button commits its page change.

page
number

Current page index. 0-based by default — set `zeroBased={false}` for 1-based indexing. Supports two-way binding.

pageCount
number

Explicit total page count. Wins over the value derived from `itemsTotal` / `itemsPerPage` — a host with server-side pagination (only one page of rows in memory) passes its known total here.

pageSizeOptions
number[]
default [10, 20, 50, 100]

Options offered by the items-per-page select.

passThrough
PaginationPassThrough<RootElementAttributes>

Per-slot escape hatch. Container slots accept `style` (merged into the slot class) and `props`; control slots forward `props` onto the child Button/Select. See the PassThrough docs.

size
"sm""md""lg"
default "sm"

Layout scale; also mirrored onto the child Button/Select `size`.

zeroBased
boolean
default true

Whether `page` uses 0-based indexing (page 0 = first page). When `false`, uses 1-based indexing (page 1 = first page).

Plus all standard <div> HTML attributes.

Type

  • Components
  • Blocks