component

Pagination

A component 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, hydrate it on the pagination runtime and drive it with paginationHydration.get(el)?.update({ … }) (@pindoba/astro-pagination/runtime) — onChangePage and the other callbacks go through update().

Default

1 - 10 / 1000
/ 100
---
// GENERATED from packages/demos/pagination/default.demo.tsx — edit the source, not this file.
import Pagination from "@pindoba/astro-pagination";

const itemsPerPage = 10;
---

<Pagination
  itemsTotal={1000}
  itemsPerPage={itemsPerPage}
  data-ir-root="pagination/default"
  data-ir="1"
/>

<script>
  import { hydrate } from "./_client/default.ts";

  document
    .querySelectorAll('[data-ir-root="pagination/default"]')
    .forEach((root) => hydrate([root]));
</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
---
// GENERATED from packages/demos/pagination/labels.demo.tsx — edit the source, not this file.
import Pagination from "@pindoba/astro-pagination";

const labels = {
  first: { visuallyHidden: false },
  previous: { visuallyHidden: false },
  next: { visuallyHidden: false },
  last: { visuallyHidden: false },
};

const itemsPerPage = 10;
---

<Pagination
  itemsTotal={100}
  itemsPerPage={itemsPerPage}
  labels={labels}
  data-ir-root="pagination/labels"
  data-ir="1"
/>

<script>
  import { hydrate } from "./_client/labels.ts";

  document
    .querySelectorAll('[data-ir-root="pagination/labels"]')
    .forEach((root) => hydrate([root]));
</script>

Localization

Every string the pagination renders is configurable through the labels prop. The control keys take static text (plus visuallyHidden); the two dynamic readouts take either a function of their values or a {placeholder} template string, so any word order works. Omitted keys keep the English defaults.

const labels: PaginationLabels = {
  first: { text: "Primeira" }, // default "First" (aria-label, icon-only)
  previous: { text: "Anterior" }, // default "Previous"
  next: { text: "Próxima" }, // default "Next"
  last: { text: "Última" }, // default "Last"
  page: { text: "Página" }, // default "Page"
  itemsPerPage: { text: "Itens por página" }, // default "Items per page"
  // default "{start} - {end} / {total}" → "1 - 10 / 95"
  summary: ({ start, end, total }) => `${start}–${end} de ${total}`,
  // default "/ {total}" → "/ 10"
  pageOf: "de {total}",
};
KeyValuesDefault
summarystart, end, total, page, totalPages"{start} - {end} / {total}"
pageOfpage, total (page count, at least 1)"/ {total}"

In Astro, prefer template strings for summary and pageOf: the component re-renders those readouts on the client, and functions can’t cross the SSR → client boundary (they’d fall back to English after the first interaction). The Table forwards its labels.pagination here.

  • Components
  • Blocks