Pagination
Page navigation with prev/next, ellipsis, and active page. Compose with your router.
Examples
Simple
Static markup with an active page and prev / next.
import { Pagination, PaginationContent, PaginationItem, PaginationLink } from "@codefast/ui/pagination";
export function PaginationSimple() {
return (
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>
2
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">3</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">4</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">5</PaginationLink>
</PaginationItem>
</PaginationContent>
</Pagination>
);
}
Icons Only
Use just the previous and next buttons without page numbers. This is useful for data tables with a rows per page selector.
import { Field, FieldLabel } from "@codefast/ui/field";
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationNext,
PaginationPrevious,
} from "@codefast/ui/pagination";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@codefast/ui/select";
export function PaginationIconsOnly() {
return (
<div className="flex items-center justify-between gap-4">
<Field orientation="horizontal" className="w-fit">
<FieldLabel htmlFor="select-rows-per-page">Rows per page</FieldLabel>
<Select defaultValue="25">
<SelectTrigger className="w-20" id="select-rows-per-page">
<SelectValue />
</SelectTrigger>
<SelectContent align="start">
<SelectGroup>
<SelectItem value="10">10</SelectItem>
<SelectItem value="25">25</SelectItem>
<SelectItem value="50">50</SelectItem>
<SelectItem value="100">100</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</Field>
<Pagination className="mx-0 w-auto">
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" />
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationContent>
</Pagination>
</div>
);
}
RTL
Right-to-left layout support for languages such as Arabic and Hebrew.
Translations are AI-generated for demonstration and may be imperfect.
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@codefast/ui/pagination";
import type { Translations } from "#/features/components-catalog/components/detail/language";
import { useTranslation } from "#/features/components-catalog/components/detail/language-context";
const translations: Translations = {
en: {
dir: "ltr",
values: {
previous: "Previous",
next: "Next",
},
},
ar: {
dir: "rtl",
values: {
previous: "السابق",
next: "التالي",
},
},
he: {
dir: "rtl",
values: {
previous: "הקודם",
next: "הבא",
},
},
};
function toArabicNumerals(num: number): string {
const arabicNumerals = ["٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"];
return num
.toString()
.split("")
.map((digit) => arabicNumerals[parseInt(digit, 10)])
.join("");
}
export function PaginationRtl() {
const { dir, t, language } = useTranslation(translations, "ar");
const formatNumber = (num: number): string => {
if (language === "ar") {
return toArabicNumerals(num);
}
return num.toString();
};
return (
<Pagination dir={dir}>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" text={t.previous ?? "Previous"} />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">{formatNumber(1)}</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>
{formatNumber(2)}
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">{formatNumber(3)}</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" text={t.next ?? "Next"} />
</PaginationItem>
</PaginationContent>
</Pagination>
);
}
Anatomy
How the parts nest — every slot the component exposes, in composition order.
Features
- Every part is a plain <a>/<li>/<nav> — wire onClick/href to your router or state yourself; there's no built-in page-state management.
- PaginationLink's isActive swaps between outline (current page) and ghost (other pages) Button variants automatically.
- PaginationPrevious/PaginationNext hide their text label below the sm breakpoint, leaving just the chevron icon.
API reference
Props for each part of the component. All native element props are also forwarded.
PaginationLink
A page link. Compose your own paginator; wire it to your router or state.
isActivebooleanMarks the current page — swaps to the outline Button variant.
PaginationPrevious
The previous-page control — disable at the lower bound via class + aria-disabled.
textstringThe label shown above the sm breakpoint.
Default
"Previous"
PaginationNext
The next-page control — disable at the upper bound via class + aria-disabled.
textstringThe label shown above the sm breakpoint.
Default
"Next"
PaginationEllipsis
A non-interactive gap marker for skipped pages. Renders a fixed MoreHorizontal icon.
classNamestringCompose additional classes onto the span.
Accessibility
Built to be keyboard-navigable and screen-reader friendly out of the box.
- Renders a nav landmark labelled “pagination”.
- Mark the current page link with aria-current="page".
- Communicate disabled prev/next with aria-disabled, not just opacity.
Guidelines
Conventions that keep usage consistent across an app.
Do
- Show first, last, current, and neighbours; collapse the rest with an ellipsis.
- Keep the active page clearly highlighted.
Don’t
- Don’t render dozens of page links — window them.
- Don’t leave prev/next clickable at the bounds.
Explore further
Ready to integrate?
Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.