<script lang="ts" module>
import { faker } from '@faker-js/faker';
const users = Array.from({ length: 500 }, (_, i) => ({
id: i + 1,
name: faker.person.fullName(),
email: faker.internet.email(),
country: faker.location.country(),
}));
const PAGE_SIZE = 5;
</script>
<script>
import { ArrowLeftIcon, ArrowRightIcon } from '@lucide/svelte';
import { Pagination } from '@skeletonlabs/skeleton-svelte';
let page = $state(1);
const start = $derived((page - 1) * PAGE_SIZE);
const end = $derived(start + PAGE_SIZE);
const data = $derived(users.slice(start, end));
</script>
<div class="grid gap-4 w-full place-items-center">
<table class="table table-auto">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Country</th>
</tr>
</thead>
<tbody>
{#each data as user}
<tr>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.country}</td>
</tr>
{/each}
</tbody>
</table>
<Pagination count={users.length} pageSize={PAGE_SIZE} {page} onPageChange={(event) => (page = event.page)}>
<Pagination.PrevTrigger>
<ArrowLeftIcon class="size-4" />
</Pagination.PrevTrigger>
<Pagination.Context>
{#snippet children(pagination)}
{#each pagination().pages as page, index (page)}
{#if page.type === 'page'}
<Pagination.Item {...page}>
{page.value}
</Pagination.Item>
{:else}
<Pagination.Ellipsis {index}>…</Pagination.Ellipsis>
{/if}
{/each}
{/snippet}
</Pagination.Context>
<Pagination.NextTrigger>
<ArrowRightIcon class="size-4" />
</Pagination.NextTrigger>
</Pagination>
</div>
| ID | Name | Country | |
|---|---|---|---|
| 1 | Lee Bashirian | Charley_Homenick@gmail.com | Solomon Islands |
| 2 | Gordon Schuppe | Rod_Medhurst74@yahoo.com | Bangladesh |
| 3 | Malcolm Pollich | Emmanuelle80@yahoo.com | Guinea-Bissau |
| 4 | Lamar Cormier | Liliana.Dickinson24@hotmail.com | Barbados |
| 5 | Lawrence O'Conner | Kariane_Hammes@yahoo.com | Saint Barthelemy |
import { faker } from '@faker-js/faker';
import { Pagination } from '@skeletonlabs/skeleton-react';
import { ArrowRightIcon, ArrowLeftIcon } from 'lucide-react';
import { useState } from 'react';
const users = Array.from({ length: 500 }, (_, i) => ({
id: i + 1,
name: faker.person.fullName(),
email: faker.internet.email(),
country: faker.location.country(),
}));
const PAGE_SIZE = 5;
export default function Default() {
const [page, setPage] = useState(1);
const start = (page - 1) * PAGE_SIZE;
const end = start + PAGE_SIZE;
const data = users.slice(start, end);
return (
<div className="grid gap-4 w-full place-items-center">
<table className="table table-auto">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Country</th>
</tr>
</thead>
<tbody>
{data.map((user) => (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.country}</td>
</tr>
))}
</tbody>
</table>
<Pagination count={users.length} pageSize={PAGE_SIZE} page={page} onPageChange={(event) => setPage(event.page)}>
<Pagination.PrevTrigger>
<ArrowLeftIcon className="size-4" />
</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>
<ArrowRightIcon className="size-4" />
</Pagination.NextTrigger>
</Pagination>
</div>
);
}
Page Size
<script lang="ts" module>
import { faker } from '@faker-js/faker';
const users = Array.from({ length: 500 }, (_, i) => ({
id: i + 1,
name: faker.person.fullName(),
email: faker.internet.email(),
country: faker.location.country(),
}));
</script>
<script>
import { ArrowLeftIcon, ArrowRightIcon } from '@lucide/svelte';
import { Pagination } from '@skeletonlabs/skeleton-svelte';
let page = $state(1);
let pageSize = $state(5);
const start = $derived((page - 1) * pageSize);
const end = $derived(start + pageSize);
const data = $derived(users.slice(start, end));
</script>
<div class="grid gap-4 w-full place-items-center">
<table class="table table-auto">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Country</th>
</tr>
</thead>
<tbody>
{#each data as user}
<tr>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.country}</td>
</tr>
{/each}
</tbody>
</table>
<div class="flex justify-between items-center gap-4 w-full">
<label class="label">
<span class="sr-only">Page Size</span>
<select class="select w-fit" value={String(pageSize)} onchange={(e) => (pageSize = Number(e.currentTarget.value))}>
<option value="5">5</option>
<option value="10">10</option>
<option value="20">20</option>
</select>
</label>
<Pagination count={users.length} {pageSize} {page} onPageChange={(event) => (page = event.page)}>
<Pagination.PrevTrigger>
<ArrowLeftIcon class="size-4" />
</Pagination.PrevTrigger>
<Pagination.Context>
{#snippet children(pagination)}
{#each pagination().pages as page, index (page)}
{#if page.type === 'page'}
<Pagination.Item {...page}>
{page.value}
</Pagination.Item>
{:else}
<Pagination.Ellipsis {index}>…</Pagination.Ellipsis>
{/if}
{/each}
{/snippet}
</Pagination.Context>
<Pagination.NextTrigger>
<ArrowRightIcon class="size-4" />
</Pagination.NextTrigger>
</Pagination>
</div>
</div>
| ID | Name | Country | |
|---|---|---|---|
| 1 | Myron Beatty | Damaris_Klein60@hotmail.com | Eswatini |
| 2 | Kari Barrows | Freeman92@gmail.com | Nauru |
| 3 | Charlie Harris | Caitlyn_Kshlerin51@gmail.com | Chile |
| 4 | Lois Pfeffer | Frances.Reynolds@hotmail.com | Philippines |
| 5 | Gordon Hyatt | Meredith94@hotmail.com | Virgin Islands, British |
import { faker } from '@faker-js/faker';
import { Pagination } from '@skeletonlabs/skeleton-react';
import { ArrowRightIcon, ArrowLeftIcon } from 'lucide-react';
import { useState } from 'react';
const users = Array.from({ length: 500 }, (_, i) => ({
id: i + 1,
name: faker.person.fullName(),
email: faker.internet.email(),
country: faker.location.country(),
}));
export default function Default() {
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(5);
const start = (page - 1) * pageSize;
const end = start + pageSize;
const data = users.slice(start, end);
return (
<div className="grid gap-4 w-full place-items-center">
<table className="table table-auto">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Country</th>
</tr>
</thead>
<tbody>
{data.map((user) => (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.country}</td>
</tr>
))}
</tbody>
</table>
<div className="flex justify-between items-center gap-4 w-full">
<label className="label">
<span className="sr-only">Page Size</span>
<select className="select w-fit" value={String(pageSize)} onChange={(e) => setPageSize(Number(e.currentTarget.value))}>
<option value="5">5</option>
<option value="10">10</option>
<option value="20">20</option>
</select>
</label>
<Pagination count={users.length} pageSize={pageSize} page={page} onPageChange={(event) => setPage(event.page)}>
<Pagination.PrevTrigger>
<ArrowLeftIcon className="size-4" />
</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>
<ArrowRightIcon className="size-4" />
</Pagination.NextTrigger>
</Pagination>
</div>
</div>
);
}
Direction
<script lang="ts" module>
import { faker } from '@faker-js/faker';
const users = Array.from({ length: 500 }, (_, i) => ({
id: i + 1,
name: faker.person.fullName(),
email: faker.internet.email(),
country: faker.location.country(),
}));
const PAGE_SIZE = 5;
</script>
<script>
import { ArrowLeftIcon, ArrowRightIcon } from '@lucide/svelte';
import { Pagination } from '@skeletonlabs/skeleton-svelte';
let page = $state(1);
const start = $derived((page - 1) * PAGE_SIZE);
const end = $derived(start + PAGE_SIZE);
const data = $derived(users.slice(start, end));
</script>
<div class="grid gap-4 w-full place-items-center">
<table class="table table-auto">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Country</th>
</tr>
</thead>
<tbody>
{#each data as user}
<tr>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.country}</td>
</tr>
{/each}
</tbody>
</table>
<Pagination count={users.length} pageSize={PAGE_SIZE} {page} onPageChange={(event) => (page = event.page)} dir="rtl">
<Pagination.PrevTrigger>
<ArrowRightIcon class="size-4" />
</Pagination.PrevTrigger>
<Pagination.Context>
{#snippet children(pagination)}
{#each pagination().pages as page, index (page)}
{#if page.type === 'page'}
<Pagination.Item {...page}>
{page.value}
</Pagination.Item>
{:else}
<Pagination.Ellipsis {index}>…</Pagination.Ellipsis>
{/if}
{/each}
{/snippet}
</Pagination.Context>
<Pagination.NextTrigger>
<ArrowLeftIcon class="size-4" />
</Pagination.NextTrigger>
</Pagination>
</div>
| ID | Name | Country | |
|---|---|---|---|
| 1 | Juana Armstrong | Rosemary_Tromp6@yahoo.com | Estonia |
| 2 | Iris Hegmann | Freddy.Ward@hotmail.com | Ethiopia |
| 3 | Stuart Stokes | Forrest_Denesik44@yahoo.com | Azerbaijan |
| 4 | Agnes Denesik | Ewell42@yahoo.com | Palestine |
| 5 | Theodore Hayes | Rex2@gmail.com | Moldova |
import { faker } from '@faker-js/faker';
import { Pagination } from '@skeletonlabs/skeleton-react';
import { ArrowRightIcon, ArrowLeftIcon } from 'lucide-react';
import { useState } from 'react';
const users = Array.from({ length: 500 }, (_, i) => ({
id: i + 1,
name: faker.person.fullName(),
email: faker.internet.email(),
country: faker.location.country(),
}));
const PAGE_SIZE = 5;
export default function Dir() {
const [page, setPage] = useState(1);
const start = (page - 1) * PAGE_SIZE;
const end = start + PAGE_SIZE;
const data = users.slice(start, end);
return (
<div className="grid gap-4 w-full place-items-center">
<table className="table table-auto">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Country</th>
</tr>
</thead>
<tbody>
{data.map((user) => (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.country}</td>
</tr>
))}
</tbody>
</table>
<Pagination count={users.length} pageSize={PAGE_SIZE} page={page} onPageChange={(event) => setPage(event.page)} dir="rtl">
<Pagination.PrevTrigger>
<ArrowRightIcon className="size-4" />
</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>
<ArrowLeftIcon className="size-4" />
</Pagination.NextTrigger>
</Pagination>
</div>
);
}
API Reference
Root
| Property | Default | Type |
|---|---|---|
ids | - | Partial<{ root: string; ellipsis: (index: number) => string; prevTrigger: string; nextTrigger: string; item: (page: number) => string; }> | undefined The ids of the elements in the accordion. Useful for composition. |
translations | - | IntlTranslations | undefinedSpecifies the localized strings that identifies the accessibility elements and their states |
count | - | number | undefinedTotal number of data items |
pageSize | - | number | undefinedThe controlled number of data items per page |
defaultPageSize | 10 | number | undefinedThe initial number of data items per page when rendered. Use when you don't need to control the page size of the pagination. |
siblingCount | 1 | number | undefinedNumber of pages to show beside active page |
page | - | number | undefinedThe controlled active page |
defaultPage | 1 | number | undefinedThe initial active page when rendered. Use when you don't need to control the active page of the pagination. |
onPageChange | - | ((details: PageChangeDetails) => void) | undefinedCalled when the page number is changed |
onPageSizeChange | - | ((details: PageSizeChangeDetails) => void) | undefinedCalled when the page size is changed |
type | "button" | "button" | "link" | undefinedThe type of the trigger element |
getPageUrl | - | ((details: PageUrlDetails) => string) | undefinedFunction to generate href attributes for pagination links. Only used when `type` is set to "link". |
dir | "ltr" | "ltr" | "rtl" | undefinedThe document's text/writing direction. |
getRootNode | - | (() => ShadowRoot | Node | Document) | undefinedA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron. |
element | - | ((attributes: HTMLAttributes<"nav">) => Element) | undefinedRender the element yourself |
RootProvider
| Property | Default | Type |
|---|---|---|
value | - | PaginationApi<PropTypes> |
element | - | ((attributes: HTMLAttributes<"nav">) => Element) | undefinedRender the element yourself |
RootContext
| Property | Default | Type |
|---|---|---|
children | - | (pagination: PaginationApi<PropTypes>) => ReactNode |
PrevTrigger
| Property | Default | Type |
|---|---|---|
element | - | ((attributes: HTMLAttributes<"button">) => Element) | undefinedRender the element yourself |
Item
| Property | Default | Type |
|---|---|---|
type | - | "page" |
value | - | number |
element | - | ((attributes: HTMLAttributes<"a">) => Element) | undefinedRender the element yourself |
Ellipsis
| Property | Default | Type |
|---|---|---|
index | - | number |
element | - | ((attributes: HTMLAttributes<"span">) => Element) | undefinedRender the element yourself |
NextTrigger
| Property | Default | Type |
|---|---|---|
element | - | ((attributes: HTMLAttributes<"button">) => Element) | undefinedRender the element yourself |
Total Count
For server-side pagination, your data source may be truncated. Make sure to specify the total records using count.
{ "data": [...], "pagination": { "page": 1, "limit": 10, "count": 500, } }
<Pagination page={response.pagination.page} count={response.pagination.count} pageSize={response.pagination.limit}>...</Pagination>