Pagination
Controls for moving through a paged collection one page at a time, with automatic ellipses and configurable sibling/boundary counts.
Renders inside a nav landmark with aria-label; current page button receives aria-current="page"; localisable labels via the labels prop.
import { Pagination } from '@arshad-shah/cynosure-react';
import { useState } from 'react';
export default function Example() {
const [page, setPage] = useState(1);
return <Pagination totalPages={8} currentPage={page} onPageChange={setPage} />;
}
Variants
Section titled “Variants”Use size="sm", "md" (default), or "lg" to match surrounding density.
import { Pagination } from '@arshad-shah/cynosure-react';
import { useState } from 'react';
export default function Example() {
const [page, setPage] = useState(3);
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
<Pagination totalPages={8} currentPage={page} onPageChange={setPage} size="sm" />
<Pagination totalPages={8} currentPage={page} onPageChange={setPage} size="md" />
<Pagination totalPages={8} currentPage={page} onPageChange={setPage} size="lg" />
</div>
);
}
First and last buttons
Section titled “First and last buttons”Set showFirstLast to render skip-to-first and skip-to-last buttons alongside Prev / Next.
import { Pagination } from '@arshad-shah/cynosure-react';
import { useState } from 'react';
export default function Example() {
const [page, setPage] = useState(5);
return <Pagination totalPages={20} currentPage={page} onPageChange={setPage} showFirstLast />;
}
Sibling and boundary counts
Section titled “Sibling and boundary counts”siblingCount (default 1) controls how many pages render either side of the current page; boundaryCount (default 1) controls how many pages stick to each end. Ellipses fill the gaps.
import { Pagination } from '@arshad-shah/cynosure-react';
import { useState } from 'react';
export default function Example() {
const [page, setPage] = useState(10);
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
<span style={{ fontSize: '0.875rem', color: 'var(--cynosure-color-fg-muted)' }}>
siblingCount=2, boundaryCount=2
</span>
<Pagination
totalPages={30}
currentPage={page}
onPageChange={setPage}
siblingCount={2}
boundaryCount={2}
/>
<span style={{ fontSize: '0.875rem', color: 'var(--cynosure-color-fg-muted)' }}>
siblingCount=0, boundaryCount=1
</span>
<Pagination
totalPages={30}
currentPage={page}
onPageChange={setPage}
siblingCount={0}
boundaryCount={1}
/>
</div>
);
}
Disabled
Section titled “Disabled”Pass disabled to freeze the whole control (e.g. while loading the next page).
import { Pagination } from '@arshad-shah/cynosure-react';
export default function Example() {
return <Pagination totalPages={8} currentPage={3} onPageChange={() => {}} disabled />;
}
Localised labels
Section titled “Localised labels”Use the labels prop to translate or rewrite each button’s accessible name.
import { Pagination } from '@arshad-shah/cynosure-react';
import { useState } from 'react';
export default function Example() {
const [page, setPage] = useState(2);
return (
<Pagination
totalPages={8}
currentPage={page}
onPageChange={setPage}
labels={{
previous: 'Page précédente',
next: 'Page suivante',
page: (p) => `Aller à la page ${p}`,
current: (p) => `Page ${p}, page actuelle`,
}}
aria-label="Pagination des résultats"
/>
);
}
Accessibility
Section titled “Accessibility”- The root renders a
<nav>landmark; passaria-label(default"Pagination") to name it. - Each page button receives a descriptive
aria-labellike"Go to page 4"; the current page is announced as"Page 4, current page". - The current button carries
aria-current="page"so screen readers identify the active position. - Prev / Next / First / Last buttons become
disabled(and unfocusable) at the edges of the range rather than disappearing. - Ellipsis placeholders are
aria-hidden="true"so they don’t pollute announcements.
Recipes
Section titled “Recipes”- Sync
currentPageto a?page=URL search param so deep links survive refresh. - Lower
siblingCountto0and raiseboundaryCountto2for a compact “first … current … last” layout. - Pair with a
Selectfor “items per page” controls in dense tables. - Customise
labels.pageto include the total count, e.g.(p) => `Go to page ${p} of 42`.