Mischief

64 / Wayfinding

Pagination

Page numbers with gaps where the run is broken, as buttons or as your own links.

Page 7 of 20

Installation

Copy the source into your project, or keep it behind a package.

npx shadcn@latest add Tinkerers-Labs/mischief-ui/pagination
import { Pagination } from "mischief-ui/pagination"
Also installs
  • lucide-react

Or paste it in yourself. The source imports the shared cn helper from @/lib/utils, so point that at your own copy.

registry/default/pagination/pagination.tsx
import * as React from "react"import { ChevronLeft, ChevronRight } from "lucide-react" import { cn } from "@/lib/utils" export type PaginationLink = {  page: number  children: React.ReactNode  "aria-label"?: string  "aria-current"?: "page"  className: string} export type PaginationProps = Omit<

Usage

export function Results({ page, pageCount }) {
  return (
    <Pagination
      page={page}
      pageCount={pageCount}
      onPageChange={setPage}
    />
  )
}

Where the gaps fall

Ends are always shown, the current page keeps siblingCount neighbours, and everything between collapses to an ellipsis. A gap costs a slot of its own, so a run short enough to draw whole is drawn whole rather than replaced by something no shorter.

paginationRange is exported, so the same numbers can be worked out without rendering anything -- for a summary line, or for a test.

paginationRange({ page: 7, pageCount: 20 })
// [1, "gap", 6, 7, 8, "gap", 20]

API

pagenumberThe current page, counting from one.
pageCountnumberHow many there are. One or fewer renders nothing.
onPageChange(page: number) => voidCalled with the page that was chosen.
siblingCountnumberPages either side of the current one. Defaults to 1.
boundaryCountnumberPages kept at each end. Defaults to 1.
renderLink(link: PaginationLink) => ReactNodeRenders every page as your own link.
labelstringNames the navigation. Defaults to "Pagination".

Accessibility

A navigation landmark with a name, so it can be jumped to and told apart from other navigation on the page. Every page is named in full rather than by its digit alone, and the current one carries aria-current so it is announced as where you are rather than as somewhere to go. The ellipsis is decoration and hidden. Previous and next are absent at the ends rather than present and disabled.