usePaginationui-interaction

usePagination

NewSSR SAFE

Controls dataset pagination metrics, slice bounds, and UI navigation range with ellipsis handling.

$ pnpm dlx shadcn@latest add @byphongphan/use-pagination
Requires @byphongphan in components.json
Loading preview...

Installation

$ pnpm dlx shadcn@latest add @byphongphan/use-pagination
Requires @byphongphan in components.json

Usage

In-Memory Client-Side List

import { usePagination, ELLIPSIS } from "@/shared/hooks"
interface Post { id: number title: string}
export function PostList({ posts }: { posts: Post[] }) { const { page, totalPages, range, next, prev, setPage, slice, hasPrevPage, hasNextPage, itemStart, itemEnd, } = usePagination<Post>({ totalItems: posts.length, initialPageSize: 5, siblings: 1, boundaries: 1, })
const currentPosts = slice(posts)
return ( <div className="space-y-4"> <div className="text-xs text-muted-foreground"> Showing {itemStart}–{itemEnd} of {posts.length} </div>
<ul className="divide-y border rounded-lg"> {currentPosts.map((post) => ( <li key={post.id} className="p-3 text-sm"> {post.title} </li> ))} </ul>
{/* Pagination Controls */} <div className="flex items-center gap-1 justify-center"> <button onClick={prev} disabled={!hasPrevPage}>Previous</button>
{range.map((item, idx) => item === ELLIPSIS ? ( <span key={`dots-${idx}`} className="px-2">...</span> ) : ( <button key={item} onClick={() => setPage(item)} className={item === page ? "font-bold text-primary" : ""} > {item} </button> ) )}
<button onClick={next} disabled={!hasNextPage}>Next</button> </div> </div> )}

Server-Side Data Fetching

import { useEffect, useState } from "react"import { usePagination } from "@/shared/hooks"
export function ServerSideTable() { const [data, setData] = useState([]) const [totalCount, setTotalCount] = useState(0)
const pagination = usePagination({ totalItems: totalCount, initialPageSize: 20, onChange: (newPage, newPageSize) => { // Re-fetch data on page change fetchUsers({ page: newPage, limit: newPageSize }) }, })
return ( <div> {/* Table displaying server-side data */} <span>Page {pagination.page} of {pagination.totalPages}</span> </div> )}

Features

  • Ellipsis Generation: Computes compact numeric navigation ranges with "..." tokens based on customizable siblings and boundaries.
  • Built-in Slicing (slice): Provides a memory-efficient slice(array) helper that calculates zero-based index boundaries automatically.
  • Display Indices Ready: Returns itemStart and itemEnd (1-based human display numbers) to easily render "Showing 11 to 20 of 100".
  • Dynamic Auto-Clamping: Automatically clamps the active page to totalPages whenever totalItems decreases (e.g. after searching or applying filters).
  • Navigation Shortcuts: Built-in first(), last(), prev(), and next() helpers alongside direct setPage(n).

Parameters

ParameterTypeDefaultDescription
options.totalItemsnumber—Total count of items in the entire dataset.
options.initialPagenumber1Initial page number (1-based).
options.initialPageSizenumber10Initial number of items per page.
options.siblingsnumber1Number of visible page buttons on each side of the active page.
options.boundariesnumber1Number of visible page buttons at the extreme start and end.
options.onChange(page: number, pageSize: number) => void—Optional callback fired whenever the active page or page size is modified.

Returns

Returns a UsePaginationReturn<T> object:

PropertyTypeDescription
pagenumberCurrent active page (1-based index).
pageSizenumberCurrent number of items rendered per page.
totalPagesnumberTotal calculated pages based on totalItems and pageSize.
range(number | "...")[]Computed list of page numbers and ellipsis tokens for UI button rendering.
startIndexnumberZero-based start index, ideal for items.slice(startIndex, endIndex).
endIndexnumberZero-based exclusive end index for array slicing.
itemStartnumberOne-based display index of the first item on current page (e.g. "Showing 11").
itemEndnumberOne-based display index of the last item on current page.
isFirstPagebooleanWhether currently on page 1.
isLastPagebooleanWhether currently on the last page.
hasPrevPagebooleanWhether backward navigation is possible (page > 1).
hasNextPagebooleanWhether forward navigation is possible (page < totalPages).
setPage(page: number) => voidNavigates directly to a target page with clamping.
setPageSize(pageSize: number, resetToFirstPage?: boolean) => voidUpdates page size with optional reset to page 1.
next() => voidMoves forward by 1 page.
prev() => voidMoves backward by 1 page.
first() => voidJumps directly to page 1.
last() => voidJumps directly to the final page.
slice(data: readonly T[]) => T[]Slices an arbitrary in-memory array for current page items.

Command Palette

Quick search and commands navigation