Pagination
Pagination is an interface that allows navigating between pages that contain split information, instead of being shown on a single page.
Installation
To use the pagination machine in your project, run the following command in your command line:
npm install @zag-js/pagination @zag-js/react # or yarn add @zag-js/pagination @zag-js/react
npm install @zag-js/pagination @zag-js/solid # or yarn add @zag-js/pagination @zag-js/solid
npm install @zag-js/pagination @zag-js/vue # or yarn add @zag-js/pagination @zag-js/vue
npm install @zag-js/pagination @zag-js/svelte # or yarn add @zag-js/pagination @zag-js/svelte
Anatomy
To set up the pagination correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Usage
First, import the pagination package into your project
import * as pagination from "@zag-js/pagination"
The pagination package exports two key functions:
machine— The state machine logic for the pagination widget.connect— The function that translates the machine's state to JSX attributes and event handlers.
You'll also need to provide a unique
idto theuseMachinehook. This is used to ensure that every part has a unique identifier.
import * as pagination from "@zag-js/pagination" import { useMachine, normalizeProps } from "@zag-js/react" import { data } from "./data" function Pagination() { const service = useMachine(pagination.machine, { id: "1", count: data.length, }) const api = pagination.connect(service, normalizeProps) return ( <div> {api.totalPages > 1 && ( <nav {...api.getRootProps()}> <ul> <li> <a href="#previous" {...api.getPrevTriggerProps()}> Previous <span className="visually-hidden">Page</span> </a> </li> {api.pages.map((page, i) => { if (page.type === "page") return ( <li key={page.value}> <a href={`#${page.value}`} {...api.getItemProps(page)}> {page.value} </a> </li> ) else return ( <li key={`ellipsis-${i}`}> <span {...api.getEllipsisProps({ index: i })}>…</span> </li> ) })} <li> <a href="#next" {...api.getNextTriggerProps()}> Next <span className="visually-hidden">Page</span> </a> </li> </ul> </nav> )} </div> ) }
import * as pagination from "@zag-js/pagination" import { normalizeProps, useMachine } from "@zag-js/solid" import { createMemo, createUniqueId, For } from "solid-js" import { data } from "./data" function Pagination() { const service = useMachine(pagination.machine, { id: createUniqueId(), count: data.length, }) const api = createMemo(() => pagination.connect(service, normalizeProps)) return ( <div> {api().totalPages > 1 && ( <nav {...api().getRootProps()}> <ul> <li> <a href="#previous" {...api().getPrevTriggerProps()}> Previous <span class="visually-hidden">Page</span> </a> </li> <For each={api().pages}> {(page, i) => { if (page.type === "page") return ( <li> <a href={`#${page.value}`} {...api().getItemProps(page)}> {page.value} </a> </li> ) return ( <li> <span {...api().getEllipsisProps({ index: i() })}> … </span> </li> ) }} </For> <li> <a href="#next" {...api().getNextTriggerProps()}> Next <span class="visually-hidden">Page</span> </a> </li> </ul> </nav> )} </div> ) }
<script setup> import * as pagination from "@zag-js/pagination" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" import { data } from "./data" const service = useMachine(pagination.machine, { id: "1", count: data.length, }) const api = computed(() => pagination.connect(service, normalizeProps)) </script> <template> <nav v-if="api.totalPages > 1" v-bind="api.getRootProps()"> <ul> <li> <a href="#previous" v-bind="api.getPrevTriggerProps()"> Previous <span class="visually-hidden">Page</span> </a> </li> <li v-for="(page, i) in api.pages" :key="page.type === 'page' ? page.value : `ellipsis-${i}`" > <span v-if="page.type === 'page'"> <a :href="`#${page.value}`" v-bind="api.getItemProps(page)"> {{page.value}} </a></span > <span v-else> <span v-bind="api.getEllipsisProps({ index: i })">…</span> </span> </li> <li> <a href="#next" v-bind="api.getNextTriggerProps()"> Next <span class="visually-hidden">Page</span> </a> </li> </ul> </nav> </template>
<script lang="ts"> import * as pagination from "@zag-js/pagination" import { useMachine, normalizeProps } from "@zag-js/svelte" import { data } from "./data" const id = $props.id() const service = useMachine(pagination.machine, { id, count: data.length, }) const api = $derived(pagination.connect(service, normalizeProps)) </script> <div> {#if api.totalPages > 1} <nav {...api.getRootProps()}> <ul> <li> <a href="#previous" {...api.getPrevTriggerProps()}> Previous <span class="visually-hidden">Page</span> </a> </li> {#each api.pages as page, i} {#if page.type === "page"} <li> <a href={`#${page.value}`} {...api.getItemProps(page)}> {page.value} </a> </li> {:else} <li> <span {...api.getEllipsisProps({ index: i })}>…</span> </li> {/if} {/each} <li> <a href="#next" {...api.getNextTriggerProps()}> Next <span class="visually-hidden">Page</span> </a> </li> </ul> </nav> {/if} </div>
const api = connect(service) // You can slice the data, to get data for current page const currentPageData = data.slice(api.pageRange.start, api.pageRange.end) api.page // => 1 api.setPage(3) // page => 3 api.previousPage // => 2 api.nextPage // => 4 api.pages /* [ { "type": "page", "value": 1, }, { "type": "page", "value": 2, }, { "type": "ellipsis", }, { "type": "page", "value": 3, }, { "type": "page", "value": 4, }, ] */ api.pageRange // => { start: 4, end: 13 }
Styling guide
Earlier, we mentioned that each pagination part has a data-part attribute
added to them to select and style them in the DOM.
[data-part="root"] { /* styles for the pagination's root */ } [data-part="item"] { /* styles for the pagination's items */ } [data-part="ellipsis"] { /* styles for the pagination's ellipsis */ } [data-part="prev-trigger"] { /* styles for the pagination's previous page trigger */ } [data-part="next-trigger"] { /* styles for the pagination's next page trigger */ } /* We add a data-disabled attribute to the prev/next items when on the first/last page */ [data-part="prev-trigger"][data-disabled] { /* styles for the pagination's previous page trigger when on first page */ } [data-part="next-trigger"][data-disabled] { /* styles for the pagination's next page trigger when on first page */ }
Methods and Properties
Machine Context
The pagination machine exposes the following context properties:
idsPartial<{ root: string; ellipsis: (index: number) => string; prevTrigger: string; nextTrigger: string; item: (page: number) => string; }>The ids of the elements in the accordion. Useful for composition.translationsIntlTranslationsSpecifies the localized strings that identifies the accessibility elements and their statescountnumberTotal number of data itemspageSizenumberThe controlled number of data items per pagedefaultPageSizenumberThe initial number of data items per page when rendered. Use when you don't need to control the page size of the pagination.siblingCountnumberNumber of pages to show beside active pagepagenumberThe controlled active pagedefaultPagenumberThe initial active page when rendered. Use when you don't need to control the active page of the pagination.onPageChange(details: PageChangeDetails) => voidCalled when the page number is changedonPageSizeChange(details: PageSizeChangeDetails) => voidCalled when the page size is changedtype"button" | "link"The type of the trigger elementdir"ltr" | "rtl"The document's text/writing direction.idstringThe unique identifier of the machine.getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.
Machine API
The pagination api exposes the following methods:
pagenumberThe current page.countnumberThe total number of data items.pageSizenumberThe number of data items per page.totalPagesnumberThe total number of pages.pagesPagesThe page range. Represented as an array of page numbers (including ellipsis)previousPagenumberThe previous page.nextPagenumberThe next page.pageRangePageRangeThe page range. Represented as an object with `start` and `end` properties.slice<V>(data: V[]) => V[]Function to slice an array of data based on the current page.setPageSize(size: number) => voidFunction to set the page size.setPage(page: number) => voidFunction to set the current page.goToNextPageVoidFunctionFunction to go to the next page.goToPrevPageVoidFunctionFunction to go to the previous page.goToFirstPageVoidFunctionFunction to go to the first page.goToLastPageVoidFunctionFunction to go to the last page.
Data Attributes
Edit this page on GitHub