Skip to content
  1. Keyline UI
  2. Pagination
Keyline UIComponents
  • Get started
    • Installation
    • Theming
    • Modes
    • Configuration
    • Composition
  • Actions
    • Button
    • Button group
    • Split button
    • Toggle
    • Toggle group
    • Toolbar
    • Menu
    • Menubar
    • Context menu
  • Inputs
    • Field and form
    • Checkbox
    • Checkbox group
    • Radio group
    • Switch
    • Slider
    • Segmented
    • Select
    • Native select
    • Combobox
    • Multiselect
    • Number field
    • OTP field
    • Time field
    • Date picker and calendar
    • Date range
  • Data
    • Table
    • Chart
    • Stat and meter
    • Status and badge
    • Progress
    • Skeleton
    • Empty
    • Avatar
    • Kbd
    • Marker
  • Navigation
    • Tabs
    • Breadcrumb
    • Pagination
    • Nav
    • Navigation menu
    • Command menu
  • Overlays
    • Dialog
    • Alert dialog
    • Drawer
    • Sheet
    • Popover
    • Hover card
    • Tooltip
    • Toast
    • Notice
  • Layout
    • App shell
    • Sidebar
    • Panel
    • Resizable
    • Scroll area
    • Accordion
    • Collapsible
    • Carousel
    • Inspector
    • Item
    • Direction
  • Conversation
    • Message
    • Bubble
    • Message scroller
    • Attachment
    • Questionnaire
  • Blocks
    • Shipments

Pagination

Page numbers as cells in one frame. The window always holds the same number of cells, each as wide as the largest page number, so the frame keeps its width and Previous and Next stay under your pointer. Under 360px of its own width the numbers fold into one “5 / 19” cell.

Loading the live example…

"use client"

import { useState } from "react"
import { Pagination } from "@/components/keyline/ui/pagination"

const CLIENTS = ["Lackawanna County", "Blue Cross of Pennsylvania", "Harper Collins", "Scranton Business Park", "Mount Airy Casino", "Penn Paper Supply", "Wilkes-Barre Library"]
const PER = 4
const TOTAL = 76

// a stand-in for the page your server returns
const invoices = (page: number) =>
  Array.from({ length: Math.min(PER, TOTAL - (page - 1) * PER) }, (_, i) => {
    const n = (page - 1) * PER + i
    return { id: `INV-${2207 - n}`, client: CLIENTS[(n * 3) % CLIENTS.length], amount: 180 + ((n * 437) % 9000) }
  })

export function InvoiceArchive() {
  const [page, setPage] = useState(1)

  return (
    <div className="grid gap-4">
      <ul aria-label={`Invoices, page ${page}`} className="m-0 grid list-none gap-2 p-0 text-[14px]">
        {invoices(page).map((inv) => (
          <li key={inv.id} className="grid grid-cols-[auto_1fr_auto] gap-3">
            <span className="font-kl-mono text-[13px]">{inv.id}</span>
            <span className="min-w-0 truncate">{inv.client}</span>
            <span className="tabular-nums">${inv.amount.toLocaleString("en-US")}.00</span>
          </li>
        ))}
      </ul>
      <Pagination page={page} pageCount={Math.ceil(TOTAL / PER)} onPageChange={setPage} label="Invoice pages" />
    </div>
  )
}

Installation

npx shadcn@latest add @keyline-ui/pagination

Run it where your components.json is. The first time, map the @keyline-ui registry: one command, in Installation.

Usage

import { Pagination } from "@/components/keyline/ui/pagination"
<Pagination page={page} pageCount={19} onPageChange={setPage} label="Invoice pages" />

Props

PropTypeDefaultDescription
pagenumberDefault —The current page, starting at 1.
pageCountnumber | nullDefault —How many pages. null while unknown: every cell is out of service.
onPageChange(page: number) => voidDefault —Called with the page to show.
getHref(page: number) => stringDefault —Makes each page a link, so pages can open in a new tab.
siblingsnumberDefault 1Pages shown on each side of the current one.
labelstringDefault "Pagination"Names the navigation landmark. Name what is paged.
pageLabel(page: number) => stringDefault Page nWhat a screen reader hears for each number.
layout"control" | "cell"Default "control"cell sits in a panel's or table's footer.

Inside a Table, use TablePagination, which also shows the range of rows.

Sheet 44 of 73PreviousBreadcrumbNextNav
On this page