Pagination

Move through a long collection with clear bounds.

datanavigation
Preview
Pagination preview

Page 3 of 12

When to use

  • Paged server results and long tables.
  • Lists where the page should live in the URL or state and fetch on change.

When not to use

  • Use carousel for browsing slides.
  • Use timeline with maxHeight for a scrolling feed instead of pages.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pagination",
  "type": "registry:ui",
  "title": "Pagination",
  "description": "Move through a long collection with clear bounds.",
  "categories": [
    "data"
  ],
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/pagination/pagination.tsx",
      "type": "registry:component",
      "target": "@components/manicat/pagination/pagination.tsx"
    },
    {
      "path": "registry/components/pagination/pagination.module.css",
      "type": "registry:component",
      "target": "@components/manicat/pagination/pagination.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/pagination",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/pagination",
    "markdown": "https://uiarc.dev/components/pagination/markdown",
    "tags": [
      "data",
      "navigation"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

import { useState } from "react";
import { Pagination } from "@/components/manicat/pagination/pagination";

export function PaginationExample() {
  const [page, setPage] = useState(3);

  return (
    <div className="flex w-full flex-col items-center gap-2">
      <Pagination page={page} pageCount={12} onPageChange={setPage} />
      <p className="text-xs text-(color:--text-muted)">Page {page} of 12</p>
    </div>
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Results pager Page state kept by the parent so the list below can follow it.

Results pager Page state kept by the parent so the list below can follow it. preview

Showing 41–60 of 240 results

Keyboard interactions

KeysAction
TabMoves between the previous, page, and next buttons.
Enter / SpaceGoes to that page.

Accessibility

  • Renders a nav landmark with the label as its name.
  • Page buttons are labelled "Page 3" and the current one has aria-current="page".
  • Previous and next are disabled at the ends and carry aria-labels.

Motion

  • The current page mark springs to the selected button.
  • When the window shifts, numbers slide like a belt by the number of slots moved.
  • Reduced motion jumps the mark and swaps numbers without sliding.

Responsive behavior

  • It always shows a five page window plus arrows, so it stays the same width on any screen.
  • The row wraps if its container is narrower than the buttons, and the current mark re-measures on resize.

Performance

  • Only five page buttons render regardless of pageCount; one ResizeObserver repositions the current mark.

Notes for AI

  • Use for paged server results and long tables. Use carousel for browsing slides.
  • It is fully controlled: keep page in state or the URL and fetch on onPageChange.