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 { useState } from "react";
import { Pagination } from "../Pagination";

export default function LabelsDemo() {
  const [page, setPage] = useState(0);
  const [itemsPerPage, setItemsPerPage] = useState(10);

  return (
    <Pagination
      itemsTotal={100}
      itemsPerPage={itemsPerPage}
      page={page}
      onChangePage={(next) => setPage(next)}
      onChangeItemsPerPage={(next) => setItemsPerPage(next)}
      labels={{
        first: { visuallyHidden: false },
        previous: { visuallyHidden: false },
        next: { visuallyHidden: false },
        last: { visuallyHidden: false },
      }}
    />
  );
}
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

No description yet.

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

No description yet.

onFirst svelte
() => void

No description yet.

onLast svelte
() => void

No description yet.

onNext svelte
() => void

No description yet.

onPrevious svelte
() => void

No description yet.

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