Utils
use-pagination
A headless pagination state hook with looping, dynamic totals and change callbacks
Installation
$npx litefy@latest add use-pagination
$pnpm dlx litefy@latest add use-pagination
$yarn dlx litefy@latest add use-pagination
$bun --bun litefy@latest add use-pagination
Usage
Basic Usage
Basic pagination usage with navigation controls and page indicators.
1 - 10 of 13 pages
"use client";
import {
ChevronLeft,
ChevronRight,
ChevronsLeft,
ChevronsRight,
} from "lucide-react";
import { usePagination } from "@/ui";
export default function PaginationDemo() {
const totalRecords = 128;
const pageSize = 10;
const totalPages = Math.ceil(totalRecords / pageSize);
const { index, goTo, next, previous, isFirst, isEnd } = usePagination({
base: 0,
total: totalPages,
loop: false,
});
const currentPage = index + 1;
const startRecord = index * pageSize + 1;
const endRecord = Math.min((index + 1) * pageSize, totalRecords);
const pageOptions = Array.from({ length: totalPages }, (_, i) => i + 1);
return (
<div className="flex items-center justify-between gap-4 px-4 py-3 border rounded-md w-full">
<div className="text-sm text-gray-600">
{startRecord} - {endRecord} of {Math.ceil(totalRecords / pageSize)} pages
</div>
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => goTo(0)}
disabled={isFirst}
className="px-3 py-1 text-sm border rounded hover:bg-gray-100"
>
<ChevronsLeft className="size-4" />
</button>
<button
type="button"
onClick={previous}
disabled={isFirst}
className="px-3 py-1 text-sm border rounded hover:bg-gray-100"
>
<ChevronLeft className="size-4" />
</button>
<select
value={currentPage}
onChange={(e) => goTo(Number(e.target.value) - 1)}
className="px-2 py-1 text-sm border rounded focus:outline-none focus:ring-1 focus:ring-blue-500"
>
{pageOptions.map((page) => (
<option key={page} value={page}>
Page {page}
</option>
))}
</select>
<button
type="button"
onClick={next}
disabled={isEnd}
className="px-3 py-1 text-sm border rounded hover:bg-gray-100"
>
<ChevronRight className="size-4" />
</button>
<button
type="button"
onClick={() => goTo(totalPages - 1)}
disabled={isEnd}
className="px-3 py-1 text-sm border rounded hover:bg-gray-100"
>
<ChevronsRight className="size-4" />
</button>
</div>
</div>
);
}
API Reference
usePagination
A headless hook that manages pagination state; pair it with your own navigation controls (see the demo above).
Options
| Prop | Type | Default | Description |
|---|---|---|---|
base | number | 0 | First page number; index is offset by this value |
total | number | (() => number) | - | Total page count, or a getter for dynamic totals. Required |
loop | boolean | false | Wraps to the other end when navigating past the first or last page |
onChange | (page: number) => void | - | Fired with the new page whenever it changes |
Returns
index: Current page number (starts atbase)total: Current total page countsetIndex(page | (prevPage) => page): Set the page directly or with an updater; it is normalized into the valid rangegoTo(page): Navigate to a specific pagenext(): Go to the next pageprevious(): Go to the previous pagetoFirst(): Go to the first page (base)toEnd(): Go to the last pageisFirst:truewhen on the first page (alwaysfalsewhenloopis enabled)isEnd:truewhen on the last page (alwaysfalsewhenloopis enabled)