Pagination
A navigation component that allows users to browse through pages.
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.
Examples
Learn how to use the Pagination component in your project. Let's take a look at the most basic example:
import { Pagination } from '@ark-ui/react/pagination'
export const Basic = () => (
<Pagination.Root count={5000} pageSize={10} siblingCount={2}>
<Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
<Pagination.Context>
{(pagination) =>
pagination.pages.map((page, index) =>
page.type === 'page' ? (
<Pagination.Item key={index} {...page}>
{page.value}
</Pagination.Item>
) : (
<Pagination.Ellipsis key={index} index={index}>
…
</Pagination.Ellipsis>
),
)
}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.Root>
)
import { Pagination } from '@ark-ui/solid/pagination'
import { For } from 'solid-js'
export const Basic = () => (
<Pagination.Root count={5000} pageSize={10} siblingCount={2}>
<Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
<Pagination.Context>
{(api) => (
<For each={api().pages}>
{(page, index) =>
page.type === 'page' ? (
<Pagination.Item {...page}>{page.value}</Pagination.Item>
) : (
<Pagination.Ellipsis index={index()}>…</Pagination.Ellipsis>
)
}
</For>
)}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.Root>
)
<script setup lang="ts">
import { Pagination } from '@ark-ui/vue/pagination'
</script>
<template>
<Pagination.Root :count="100" :page-size="10" :sibling-count="2">
<Pagination.PrevTrigger>
Previous
<span className="visually-hidden">Page</span>
</Pagination.PrevTrigger>
<Pagination.Context v-slot="pagination">
<template v-for="(page, index) in pagination.pages">
<Pagination.Item v-if="page.type === 'page'" :key="index" :value="page.value" :type="page.type">
{{ page.value }}
</Pagination.Item>
<Pagination.Ellipsis v-else :key="'e' + index" :index="index">…</Pagination.Ellipsis>
</template>
</Pagination.Context>
<Pagination.NextTrigger>
Next
<span className="visually-hidden">Page</span>
</Pagination.NextTrigger>
</Pagination.Root>
</template>
<script lang="ts">
import { Pagination } from '@ark-ui/svelte/pagination'
</script>
<Pagination.Root count={5000} pageSize={10} siblingCount={2}>
<Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
<Pagination.Context>
{#snippet render(pagination)}
{#each pagination().pages as page, index (index)}
{#if page.type === 'page'}
<Pagination.Item {...page}>
{page.value}
</Pagination.Item>
{:else}
<Pagination.Ellipsis {index}>…</Pagination.Ellipsis>
{/if}
{/each}
{/snippet}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.Root>
Controlled Pagination
To create a controlled Pagination component, manage the state of the current page using the page prop and update it
when the onPageChange event handler is called:
import { Pagination } from '@ark-ui/react/pagination'
import { useState } from 'react'
export const Controlled = () => {
const [currentPage, setCurrentPage] = useState(1)
return (
<Pagination.Root
count={5000}
pageSize={10}
siblingCount={2}
page={currentPage}
onPageChange={(details) => setCurrentPage(details.page)}
>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
<Pagination.Context>
{(pagination) =>
pagination.pages.map((page, index) =>
page.type === 'page' ? (
<Pagination.Item key={index} {...page}>
{page.value}
</Pagination.Item>
) : (
<Pagination.Ellipsis key={index} index={index}>
…
</Pagination.Ellipsis>
),
)
}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.Root>
)
}
import { Pagination } from '@ark-ui/solid/pagination'
import { For, createSignal } from 'solid-js'
export const Controlled = () => {
const [currentPage, setCurrentPage] = createSignal(1)
return (
<Pagination.Root
count={5000}
pageSize={10}
siblingCount={2}
page={currentPage()}
onPageChange={(details) => setCurrentPage(details.page)}
>
<Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
<Pagination.Context>
{(api) => (
<For each={api().pages}>
{(page, index) =>
page.type === 'page' ? (
<Pagination.Item {...page}>{page.value}</Pagination.Item>
) : (
<Pagination.Ellipsis index={index()}>…</Pagination.Ellipsis>
)
}
</For>
)}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.Root>
)
}
<script setup lang="ts">
import { Pagination } from '@ark-ui/vue/pagination'
import { ref } from 'vue'
const currentPage = ref(1)
</script>
<template>
<Pagination.Root :count="5000" :page-size="10" :sibling-count="2" v-model:page="currentPage">
<Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
<Pagination.Context v-slot="api">
<template v-for="(page, index) in api.pages" :key="index">
<Pagination.Item v-if="page.type === 'page'" v-bind="page">
{{ page.value }}
</Pagination.Item>
<Pagination.Ellipsis v-else :index="index">…</Pagination.Ellipsis>
</template>
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.Root>
</template>
<script lang="ts">
import { Pagination } from '@ark-ui/svelte/pagination'
let page = $state(1)
</script>
<Pagination.Root count={5000} pageSize={10} siblingCount={2} bind:page>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
<Pagination.Context>
{#snippet render(pagination)}
{#each pagination().pages as page, index (index)}
{#if page.type === 'page'}
<Pagination.Item {...page}>
{page.value}
</Pagination.Item>
{:else}
<Pagination.Ellipsis {index}>…</Pagination.Ellipsis>
{/if}
{/each}
{/snippet}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.Root>
Customizing Pagination
You can customize the Pagination component by setting various props such as dir, pageSize, siblingCount, and
translations. Here's an example of a customized Pagination:
import { Pagination } from '@ark-ui/react/pagination'
export const Customized = () => (
<Pagination.Root
count={5000}
pageSize={20}
siblingCount={3}
translations={{
nextTriggerLabel: 'Next',
prevTriggerLabel: 'Prev',
itemLabel: (details) => `Page ${details.page}`,
}}
>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
<Pagination.Context>
{(pagination) =>
pagination.pages.map((page, index) =>
page.type === 'page' ? (
<Pagination.Item key={index} {...page}>
{page.value}
</Pagination.Item>
) : (
<Pagination.Ellipsis key={index} index={index}>
…
</Pagination.Ellipsis>
),
)
}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.Root>
)
import { Pagination } from '@ark-ui/solid/pagination'
import { For } from 'solid-js'
export const Customized = () => {
return (
<Pagination.Root
count={5000}
pageSize={20}
siblingCount={3}
translations={{
nextTriggerLabel: 'Next',
prevTriggerLabel: 'Prev',
itemLabel: (details) => `Page ${details.page}`,
}}
>
<Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
<Pagination.Context>
{(api) => (
<For each={api().pages}>
{(page, index) =>
page.type === 'page' ? (
<Pagination.Item {...page}>{page.value}</Pagination.Item>
) : (
<Pagination.Ellipsis index={index()}>…</Pagination.Ellipsis>
)
}
</For>
)}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.Root>
)
}
<script setup lang="ts">
import { Pagination } from '@ark-ui/vue/pagination'
</script>
<template>
<Pagination.Root
:count="5000"
:page-size="20"
:sibling-count="3"
:translations="{
nextTriggerLabel: 'Next',
prevTriggerLabel: 'Prev',
itemLabel: (details) => `Page ${details.page}`,
}"
>
<Pagination.PrevTrigger>
Previous
<span className="visually-hidden">Page</span>
</Pagination.PrevTrigger>
<Pagination.Context v-slot="pagination">
<template v-for="(page, index) in pagination.pages">
<Pagination.Item v-if="page.type === 'page'" :key="index" :value="page.value" :type="page.type">
{{ page.value }}
</Pagination.Item>
<Pagination.Ellipsis v-else :key="'e' + index" :index="index">…</Pagination.Ellipsis>
</template>
</Pagination.Context>
<Pagination.NextTrigger>
Next
<span className="visually-hidden">Page</span>
</Pagination.NextTrigger>
</Pagination.Root>
</template>
<script lang="ts">
import { Pagination } from '@ark-ui/svelte/pagination'
</script>
<Pagination.Root
count={5000}
pageSize={20}
siblingCount={3}
translations={{
nextTriggerLabel: 'Next',
prevTriggerLabel: 'Prev',
itemLabel: (details) => `Page ${details.page}`,
}}
>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
<Pagination.Context>
{#snippet render(pagination)}
{#each pagination().pages as page, index (index)}
{#if page.type === 'page'}
<Pagination.Item {...page}>
{page.value}
</Pagination.Item>
{:else}
<Pagination.Ellipsis {index}>…</Pagination.Ellipsis>
{/if}
{/each}
{/snippet}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.Root>
Using Context
The Context component provides access to the pagination state and methods through a render prop pattern. This allows
you to access methods like setPage, setPageSize, goToNextPage, goToPrevPage, goToFirstPage, goToLastPage, as
well as properties like totalPages and pageRange.
import { Pagination } from '@ark-ui/react/pagination'
export const Context = () => {
return (
<Pagination.Root count={100} pageSize={10}>
<Pagination.Context>
{(pagination) => (
<div>
<button onClick={() => pagination.goToFirstPage()}>First</button>
<button onClick={() => pagination.goToPrevPage()}>Previous</button>
<button onClick={() => pagination.setPage(5)}>Go to Page 5</button>
<button onClick={() => pagination.goToNextPage()}>Next</button>
<button onClick={() => pagination.goToLastPage()}>Last</button>
<p>
Page {pagination.page} of {pagination.totalPages}
</p>
<p>
Items {pagination.pageRange.start + 1}-{pagination.pageRange.end}
</p>
<button onClick={() => pagination.setPageSize(20)}>20 per page</button>
</div>
)}
</Pagination.Context>
</Pagination.Root>
)
}
import { Pagination } from '@ark-ui/solid/pagination'
export const Context = () => {
return (
<Pagination.Root count={100} pageSize={10}>
<Pagination.Context>
{(api) => (
<div>
<button onClick={() => api().goToFirstPage()}>First</button>
<button onClick={() => api().goToPrevPage()}>Previous</button>
<button onClick={() => api().setPage(5)}>Go to Page 5</button>
<button onClick={() => api().goToNextPage()}>Next</button>
<button onClick={() => api().goToLastPage()}>Last</button>
<p>
Page {api().page} of {api().totalPages}
</p>
<p>
Items {api().pageRange.start + 1}-{api().pageRange.end}
</p>
<button onClick={() => api().setPageSize(20)}>20 per page</button>
</div>
)}
</Pagination.Context>
</Pagination.Root>
)
}
<script setup lang="ts">
import { Pagination } from '@ark-ui/vue/pagination'
</script>
<template>
<Pagination.Root :count="100" :pageSize="10">
<Pagination.Context v-slot="pagination">
<div>
<button @click="pagination.goToFirstPage()">First</button>
<button @click="pagination.goToPrevPage()">Previous</button>
<button @click="pagination.setPage(5)">Go to Page 5</button>
<button @click="pagination.goToNextPage()">Next</button>
<button @click="pagination.goToLastPage()">Last</button>
<p>Page {{ pagination.page }} of {{ pagination.totalPages }}</p>
<p>Items {{ pagination.pageRange.start + 1 }}-{{ pagination.pageRange.end }}</p>
<button @click="pagination.setPageSize(20)">20 per page</button>
</div>
</Pagination.Context>
</Pagination.Root>
</template>
<script lang="ts">
import { Pagination } from '@ark-ui/svelte/pagination'
</script>
<Pagination.Root count={100} pageSize={10}>
<Pagination.Context>
{#snippet render(pagination)}
<div>
<button onclick={() => pagination().goToFirstPage()}>First</button>
<button onclick={() => pagination().goToPrevPage()}>Previous</button>
<button onclick={() => pagination().setPage(5)}>Go to Page 5</button>
<button onclick={() => pagination().goToNextPage()}>Next</button>
<button onclick={() => pagination().goToLastPage()}>Last</button>
<p>Page {pagination().page} of {pagination().totalPages}</p>
<p>Items {pagination().pageRange.start + 1}-{pagination().pageRange.end}</p>
<button onclick={() => pagination().setPageSize(20)}>20 per page</button>
</div>
{/snippet}
</Pagination.Context>
</Pagination.Root>
Data Slicing
Use the slice() method to paginate actual data arrays. This method automatically slices your data based on the current
page and page size.
import { Pagination } from '@ark-ui/react/pagination'
const items = Array.from({ length: 100 }, (_, i) => `Item ${i + 1}`)
export const DataSlicing = () => {
return (
<Pagination.Root count={items.length} pageSize={10}>
<Pagination.Context>
{(pagination) => (
<div>
<div>
<h3>Current Page Items:</h3>
<ul>
{pagination.slice(items).map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
{pagination.pages.map((page, index) =>
page.type === 'page' ? (
<Pagination.Item key={index} {...page}>
{page.value}
</Pagination.Item>
) : (
<Pagination.Ellipsis key={index} index={index}>
…
</Pagination.Ellipsis>
),
)}
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
</div>
)}
</Pagination.Context>
</Pagination.Root>
)
}
import { Pagination } from '@ark-ui/solid/pagination'
import { For } from 'solid-js'
const items = Array.from({ length: 100 }, (_, i) => `Item ${i + 1}`)
export const DataSlicing = () => {
return (
<Pagination.Root count={items.length} pageSize={10}>
<Pagination.Context>
{(api) => (
<div>
<div>
<h3>Current Page Items:</h3>
<ul>
<For each={api().slice(items)}>{(item) => <li>{item}</li>}</For>
</ul>
</div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
<For each={api().pages}>
{(page, index) =>
page.type === 'page' ? (
<Pagination.Item {...page}>{page.value}</Pagination.Item>
) : (
<Pagination.Ellipsis index={index()}>…</Pagination.Ellipsis>
)
}
</For>
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
</div>
)}
</Pagination.Context>
</Pagination.Root>
)
}
<script setup lang="ts">
import { Pagination } from '@ark-ui/vue/pagination'
const items = Array.from({ length: 100 }, (_, i) => `Item ${i + 1}`)
</script>
<template>
<Pagination.Root :count="items.length" :pageSize="10">
<Pagination.Context v-slot="pagination">
<div>
<div>
<h3>Current Page Items:</h3>
<ul>
<li v-for="item in pagination.slice(items)" :key="item">{{ item }}</li>
</ul>
</div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
<template v-for="(page, index) in pagination.pages" :key="index">
<Pagination.Item v-if="page.type === 'page'" :value="page.value" :type="page.type">
{{ page.value }}
</Pagination.Item>
<Pagination.Ellipsis v-else :index="index">…</Pagination.Ellipsis>
</template>
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
</div>
</Pagination.Context>
</Pagination.Root>
</template>
<script lang="ts">
import { Pagination } from '@ark-ui/svelte/pagination'
const items = Array.from({ length: 100 }, (_, i) => `Item ${i + 1}`)
</script>
<Pagination.Root count={items.length} pageSize={10}>
<Pagination.Context>
{#snippet render(pagination)}
<div>
<div>
<h3>Current Page Items:</h3>
<ul>
{#each pagination().slice(items) as item}
<li>{item}</li>
{/each}
</ul>
</div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
{#each pagination().pages as page, index}
{#if page.type === 'page'}
<Pagination.Item {...page}>{page.value}</Pagination.Item>
{:else}
<Pagination.Ellipsis {index}>…</Pagination.Ellipsis>
{/if}
{/each}
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
</div>
{/snippet}
</Pagination.Context>
</Pagination.Root>
Page Range Display
Display the current page range information using the pageRange property. This shows which items are currently visible
(e.g., "Showing 1-10 of 100 results").
import { Pagination } from '@ark-ui/react/pagination'
export const PageRange = () => {
return (
<Pagination.Root count={100} pageSize={10}>
<Pagination.Context>
{(pagination) => (
<div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
{pagination.pages.map((page, index) =>
page.type === 'page' ? (
<Pagination.Item key={index} {...page}>
{page.value}
</Pagination.Item>
) : (
<Pagination.Ellipsis key={index} index={index}>
…
</Pagination.Ellipsis>
),
)}
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
<div>
<p>
Showing {pagination.pageRange.start + 1}-{pagination.pageRange.end} of {pagination.count} results
</p>
<p>
Page {pagination.page} of {pagination.totalPages}
</p>
</div>
</div>
)}
</Pagination.Context>
</Pagination.Root>
)
}
import { Pagination } from '@ark-ui/solid/pagination'
import { For } from 'solid-js'
export const PageRange = () => {
return (
<Pagination.Root count={100} pageSize={10}>
<Pagination.Context>
{(api) => (
<div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
<For each={api().pages}>
{(page, index) =>
page.type === 'page' ? (
<Pagination.Item {...page}>{page.value}</Pagination.Item>
) : (
<Pagination.Ellipsis index={index()}>…</Pagination.Ellipsis>
)
}
</For>
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
<div>
<p>
Showing {api().pageRange.start + 1}-{api().pageRange.end} of {api().count} results
</p>
<p>
Page {api().page} of {api().totalPages}
</p>
</div>
</div>
)}
</Pagination.Context>
</Pagination.Root>
)
}
<script setup lang="ts">
import { Pagination } from '@ark-ui/vue/pagination'
</script>
<template>
<Pagination.Root :count="100" :pageSize="10">
<Pagination.Context v-slot="pagination">
<div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
<template v-for="(page, index) in pagination.pages" :key="index">
<Pagination.Item v-if="page.type === 'page'" :value="page.value" :type="page.type">
{{ page.value }}
</Pagination.Item>
<Pagination.Ellipsis v-else :index="index">…</Pagination.Ellipsis>
</template>
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
<div>
<p>
Showing {{ pagination.pageRange.start + 1 }}-{{ pagination.pageRange.end }} of
{{ pagination.count }} results
</p>
<p>Page {{ pagination.page }} of {{ pagination.totalPages }}</p>
</div>
</div>
</Pagination.Context>
</Pagination.Root>
</template>
<script lang="ts">
import { Pagination } from '@ark-ui/svelte/pagination'
</script>
<Pagination.Root count={100} pageSize={10}>
<Pagination.Context>
{#snippet render(pagination)}
<div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
{#each pagination().pages as page, index}
{#if page.type === 'page'}
<Pagination.Item {...page}>{page.value}</Pagination.Item>
{:else}
<Pagination.Ellipsis {index}>…</Pagination.Ellipsis>
{/if}
{/each}
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
<div>
<p>
Showing {pagination().pageRange.start + 1}-{pagination().pageRange.end} of {pagination().count} results
</p>
<p>
Page {pagination().page} of {pagination().totalPages}
</p>
</div>
</div>
{/snippet}
</Pagination.Context>
</Pagination.Root>
Page Size Control
Control the number of items per page dynamically using setPageSize(). This example shows how to integrate a native
select element to change the page size.
import { Pagination } from '@ark-ui/react/pagination'
export const PageSizeControl = () => {
return (
<Pagination.Root count={100} pageSize={10}>
<Pagination.Context>
{(pagination) => (
<div>
<div>
<label>Items per page: </label>
<select value={pagination.pageSize} onChange={(e) => pagination.setPageSize(Number(e.target.value))}>
<option value={5}>5</option>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={50}>50</option>
</select>
</div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
{pagination.pages.map((page, index) =>
page.type === 'page' ? (
<Pagination.Item key={index} {...page}>
{page.value}
</Pagination.Item>
) : (
<Pagination.Ellipsis key={index} index={index}>
…
</Pagination.Ellipsis>
),
)}
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
<p>
Page {pagination.page} of {pagination.totalPages}
</p>
</div>
)}
</Pagination.Context>
</Pagination.Root>
)
}
import { Pagination } from '@ark-ui/solid/pagination'
import { For } from 'solid-js'
export const PageSizeControl = () => {
return (
<Pagination.Root count={100} pageSize={10}>
<Pagination.Context>
{(api) => (
<div>
<div>
<label>Items per page: </label>
<select value={api().pageSize} onChange={(e) => api().setPageSize(Number(e.target.value))}>
<option value={5}>5</option>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={50}>50</option>
</select>
</div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
<For each={api().pages}>
{(page, index) =>
page.type === 'page' ? (
<Pagination.Item {...page}>{page.value}</Pagination.Item>
) : (
<Pagination.Ellipsis index={index()}>…</Pagination.Ellipsis>
)
}
</For>
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
<p>
Page {api().page} of {api().totalPages}
</p>
</div>
)}
</Pagination.Context>
</Pagination.Root>
)
}
<script setup lang="ts">
import { Pagination } from '@ark-ui/vue/pagination'
</script>
<template>
<Pagination.Root :count="100" :pageSize="10">
<Pagination.Context v-slot="pagination">
<div>
<div>
<label>Items per page:</label>
<select
:value="pagination.pageSize"
@change="(event) => pagination.setPageSize(Number((event.currentTarget as HTMLSelectElement).value))"
>
<option :value="5">5</option>
<option :value="10">10</option>
<option :value="20">20</option>
<option :value="50">50</option>
</select>
</div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
<template v-for="(page, index) in pagination.pages" :key="index">
<Pagination.Item v-if="page.type === 'page'" :value="page.value" :type="page.type">
{{ page.value }}
</Pagination.Item>
<Pagination.Ellipsis v-else :index="index">…</Pagination.Ellipsis>
</template>
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
<p>Page {{ pagination.page }} of {{ pagination.totalPages }}</p>
</div>
</Pagination.Context>
</Pagination.Root>
</template>
<script lang="ts">
import { Pagination } from '@ark-ui/svelte/pagination'
</script>
<Pagination.Root count={100} pageSize={10}>
<Pagination.Context>
{#snippet render(pagination)}
<div>
<div>
<label for="page-size">Items per page:</label>
<select
id="page-size"
value={pagination().pageSize}
onchange={(e) => pagination().setPageSize(Number(e.currentTarget.value))}
>
<option value={5}>5</option>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={50}>50</option>
</select>
</div>
<div>
<Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
{#each pagination().pages as page, index}
{#if page.type === 'page'}
<Pagination.Item {...page}>{page.value}</Pagination.Item>
{:else}
<Pagination.Ellipsis {index}>…</Pagination.Ellipsis>
{/if}
{/each}
<Pagination.NextTrigger>Next</Pagination.NextTrigger>
</div>
<p>
Page {pagination().page} of {pagination().totalPages}
</p>
</div>
{/snippet}
</Pagination.Context>
</Pagination.Root>
Link Pagination
Create pagination with link navigation for better SEO and accessibility. This example shows how to use the pagination component with anchor links instead of buttons.
import { Pagination, usePagination } from '@ark-ui/react/pagination'
export const Link = () => {
const pagination = usePagination({
type: 'link',
count: 100,
pageSize: 10,
siblingCount: 2,
getPageUrl: ({ page }) => `/page=${page}`,
})
return (
<Pagination.RootProvider value={pagination}>
<a {...pagination.getPrevTriggerProps()}>Previous</a>
{pagination.pages.map((page, index) =>
page.type === 'page' ? (
<a key={index} {...pagination.getItemProps(page)}>
{page.value}
</a>
) : (
<span key={index} {...pagination.getEllipsisProps({ index })}>
…
</span>
),
)}
<a {...pagination.getNextTriggerProps()}>Next</a>
</Pagination.RootProvider>
)
}
import { Pagination, usePagination } from '@ark-ui/solid/pagination'
import { For } from 'solid-js'
export const Link = () => {
const pagination = usePagination({
type: 'link',
count: 100,
pageSize: 10,
siblingCount: 2,
getPageUrl: ({ page }) => `/page=${page}`,
})
return (
<Pagination.RootProvider value={pagination}>
<a {...pagination().getPrevTriggerProps()}>Previous</a>
<For each={pagination().pages}>
{(page, index) =>
page.type === 'page' ? (
<a {...pagination().getItemProps(page)}>{page.value}</a>
) : (
<span {...pagination().getEllipsisProps({ index: index() })}>…</span>
)
}
</For>
<a {...pagination().getNextTriggerProps()}>Next</a>
</Pagination.RootProvider>
)
}
<script setup lang="ts">
import { Pagination, usePagination } from '@ark-ui/vue/pagination'
const pagination = usePagination({
type: 'link',
count: 100,
pageSize: 10,
siblingCount: 2,
getPageUrl: ({ page }) => `/page=${page}`,
})
</script>
<template>
<Pagination.RootProvider :value="pagination">
<a v-bind="pagination.getPrevTriggerProps()">Previous</a>
<template v-for="(page, index) in pagination.pages" :key="index">
<a v-if="page.type === 'page'" v-bind="pagination.getItemProps(page)">
{{ page.value }}
</a>
<span v-else v-bind="pagination.getEllipsisProps({ index })">…</span>
</template>
<a v-bind="pagination.getNextTriggerProps()">Next</a>
</Pagination.RootProvider>
</template>
<script lang="ts">
import { Pagination, usePagination } from '@ark-ui/svelte/pagination'
const id = $props.id()
const pagination = usePagination({
id,
type: 'link',
count: 100,
pageSize: 10,
siblingCount: 2,
getPageUrl: ({ page }) => `/page=${page}`,
})
</script>
<Pagination.RootProvider value={pagination}>
<a {...pagination().getPrevTriggerProps()}>Previous</a>
{#each pagination().pages as page, index (index)}
{#if page.type === 'page'}
<a {...pagination().getItemProps(page)}>{page.value}</a>
{:else}
<span {...pagination().getEllipsisProps({ index })}>…</span>
{/if}
{/each}
<a {...pagination().getNextTriggerProps()}>Next</a>
</Pagination.RootProvider>
Root Provider
The RootProvider component provides a context for the pagination. It accepts the value of the usePagination hook.
You can leverage it to access the component state and methods from outside the pagination.
import { Pagination, usePagination } from '@ark-ui/react/pagination'
export const RootProvider = () => {
const pagination = usePagination({ count: 5000, pageSize: 10, siblingCount: 2 })
return (
<>
<button onClick={() => pagination.goToNextPage()}>Next Page</button>
<Pagination.RootProvider value={pagination}>
<Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
<Pagination.Context>
{(pagination) =>
pagination.pages.map((page, index) =>
page.type === 'page' ? (
<Pagination.Item key={index} {...page}>
{page.value}
</Pagination.Item>
) : (
<Pagination.Ellipsis key={index} index={index}>
…
</Pagination.Ellipsis>
),
)
}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.RootProvider>
</>
)
}
import { Pagination, usePagination } from '@ark-ui/solid/pagination'
import { For } from 'solid-js'
export const RootProvider = () => {
const pagination = usePagination({ count: 5000, pageSize: 10, siblingCount: 2 })
return (
<>
<button onClick={() => pagination().goToNextPage()}>Next Page</button>
<Pagination.RootProvider value={pagination}>
<Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
<Pagination.Context>
{(api) => (
<For each={api().pages}>
{(page, index) =>
page.type === 'page' ? (
<Pagination.Item {...page}>{page.value}</Pagination.Item>
) : (
<Pagination.Ellipsis index={index()}>…</Pagination.Ellipsis>
)
}
</For>
)}
</Pagination.Context>
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.RootProvider>
</>
)
}
<script setup lang="ts">
import { Pagination, usePagination } from '@ark-ui/vue/pagination'
const pagination = usePagination({ count: 100, pageSize: 10, siblingCount: 2 })
</script>
<template>
<button @click="pagination.goToNextPage()">Next Page</button>
<Pagination.RootProvider :value="pagination">
<Pagination.PrevTrigger>
Previous
<span className="visually-hidden">Page</span>
</Pagination.PrevTrigger>
<Pagination.Context v-slot="pagination">
<template v-for="(page, index) in pagination.pages">
<Pagination.Item v-if="page.type === 'page'" :key="index" :value="page.value" :type="page.type">
{{ page.value }}
</Pagination.Item>
<Pagination.Ellipsis v-else :key="'e' + index" :index="index">…</Pagination.Ellipsis>
</template>
</Pagination.Context>
<Pagination.NextTrigger>
Next
<span className="visually-hidden">Page</span>
</Pagination.NextTrigger>
</Pagination.RootProvider>
</template>
<script lang="ts">
import { Pagination, usePagination } from '@ark-ui/svelte/pagination'
const id = $props.id()
const pagination = usePagination({
id,
count: 5000,
pageSize: 10,
siblingCount: 2,
})
</script>
<button onclick={() => pagination().goToNextPage()}>Next Page</button>
<Pagination.RootProvider value={pagination}>
<Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
{#each pagination().pages as page, index (index)}
{#if page.type === 'page'}
<Pagination.Item {...page}>
{page.value}
</Pagination.Item>
{:else}
<Pagination.Ellipsis {index}>…</Pagination.Ellipsis>
{/if}
{/each}
<Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
</Pagination.RootProvider>
If you're using the
RootProvidercomponent, you don't need to use theRootcomponent.
API Reference
Root
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
count | numberTotal number of data items | |
defaultPage | 1 | numberThe initial active page when rendered. Use when you don't need to control the active page of the pagination. |
defaultPageSize | 10 | numberThe initial number of data items per page when rendered. Use when you don't need to control the page size of the pagination. |
ids | Partial<{
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. | |
onPageChange | (details: PageChangeDetails) => voidCalled when the page number is changed | |
onPageSizeChange | (details: PageSizeChangeDetails) => voidCalled when the page size is changed | |
page | numberThe controlled active page | |
pageSize | numberThe controlled number of data items per page | |
siblingCount | 1 | numberNumber of pages to show beside active page |
translations | IntlTranslationsSpecifies the localized strings that identifies the accessibility elements and their states | |
type | 'button' | 'button' | 'link'The type of the trigger element |
Ellipsis
| Prop | Default | Type |
|---|---|---|
index | number | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Item
| Prop | Default | Type |
|---|---|---|
type | 'page' | |
value | number | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | pagination |
[data-part] | item |
[data-index] | The index of the item |
[data-selected] | Present when selected |
NextTrigger
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | pagination |
[data-part] | next-trigger |
[data-disabled] | Present when disabled |
PrevTrigger
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | pagination |
[data-part] | prev-trigger |
[data-disabled] | Present when disabled |
RootProvider
| Prop | Default | Type |
|---|---|---|
value | UsePaginationReturn | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |