Skip to main contentSkip to docs navigation

Pagination

Chassis React Pagination supports both a smart data-driven mode (pass total pages and current page) and manual markup with PaginationItem.

Smart pagination

Pass pages, activePage, and onActivePageChange to let <Pagination> render the full control automatically — Prev/Next buttons, page numbers, and ellipsis for lg ranges. The Prev/Next controls default to English accessible names ("Previous"/"Next"); override them with previousLabel/nextLabel for other locales — see Internationalization for why these labels aren't locale-driven automatically.

JSX
import { useState } from 'react'
import { Pagination } from '@chassis-ui/react'

export const Example = () => {
  const [page, setPage] = useState(1)
  return <Pagination pages={10} activePage={page} onActivePageChange={setPage} aria-label="Demo" />
}

Max visible pages

Use maxVisiblePages to control how many page buttons appear before collapsing to ellipsis (default is 5).

JSX
import { useState } from 'react'
import { Pagination } from '@chassis-ui/react'

export const Example = () => {
  const [page, setPage] = useState(5)
  return (
    <Pagination
      pages={20}
      activePage={page}
      onActivePageChange={setPage}
      maxVisiblePages={7}
      aria-label="Demo"
    />
  )
}

Partial controls

Set showPageNumbers={false} for a Prev/Next-only paginator, or showPrevNext={false} for a page-numbers-only one. Both default to true.

JSX
import { useState } from 'react'
import { Pagination } from '@chassis-ui/react'

export const Example = () => {
  const [page, setPage] = useState(1)
  // const [numbersPage, setNumbersPage] = useState(1)

  return (
    <div className="d-flex justify-content-between flex-wrap gap-md">
      <Pagination
        pages={5}
        activePage={page}
        onActivePageChange={setPage}
        showPrevNext={false}
        aria-label="Numbers only"
      />
      <Pagination
        pages={5}
        activePage={page}
        onActivePageChange={setPage}
        showPageNumbers={false}
        aria-label="Directions only"
      />
    </div>
  )
}

Manual markup

For sets that smart mode's contiguous-range-plus-ellipsis algorithm can't produce — like a fixed list of bookmarked pages — compose the pagination using <PaginationItem> directly.

JSX
import { useState } from 'react'
import { Pagination, PaginationItem, usePagination } from '@chassis-ui/react'

// Smart mode always shows a contiguous range around the active page. Manual mode is for sets
// smart mode can't produce — like jumping between a fixed list of bookmarked pages. Prev/Next
// step through the array by index rather than by ±1, since the page numbers themselves aren't
// contiguous.
const bookmarkedPages = [1, 5, 12, 47]

export const Example = () => {
  const [index, setIndex] = useState(0)

  const prevDisabled = index <= 0
  const nextDisabled = index >= bookmarkedPages.length - 1
  const { prevRef, nextRef, handlePrevClick, handleNextClick } = usePagination({
    prevDisabled,
    nextDisabled,
    onPrev: () => setIndex((i) => i - 1),
    onNext: () => setIndex((i) => i + 1)
  })

  return (
    <Pagination aria-label="Bookmarked pages">
      <PaginationItem
        ref={prevRef}
        disabled={prevDisabled}
        onClick={handlePrevClick}
        aria-label="Previous"
      >
        &laquo;
      </PaginationItem>
      {bookmarkedPages.map((p, i) => (
        <PaginationItem key={p} active={i === index} onClick={() => setIndex(i)}>
          {p}
        </PaginationItem>
      ))}
      <PaginationItem
        ref={nextRef}
        disabled={nextDisabled}
        onClick={handleNextClick}
        aria-label="Next"
      >
        &raquo;
      </PaginationItem>
    </Pagination>
  )
}

Smart mode always renders buttons. Pass href to PaginationItem for real anchors instead — e.g. server-rendered pages where each link is a full page load to a URL like ?page=2.

JSX
import { Pagination, PaginationItem } from '@chassis-ui/react'

// Smart mode always renders buttons wired to `onActivePageChange`. Pass `href` directly to
// `PaginationItem` for real anchors instead — e.g. server-rendered pages where each link is a
// full page load to `?page=N`. (Hrefs point to `#` here so the docs page itself doesn't
// navigate; swap in your real page URLs.)
export const Example = () => {
  return (
    <Pagination aria-label="Page navigation example">
      <PaginationItem href="#" aria-label="Previous" disabled>
        &laquo;
      </PaginationItem>
      <PaginationItem href="#" active>
        1
      </PaginationItem>
      <PaginationItem href="#">2</PaginationItem>
      <PaginationItem href="#">3</PaginationItem>
      <PaginationItem href="#" aria-label="Next">
        &raquo;
      </PaginationItem>
    </Pagination>
  )
}

Loading state

Disable every item while the paginated data is fetching, so the control visibly reflects the loading state instead of accepting clicks that only queue up once the fetch resolves.

JSX
import { Pagination, PaginationItem } from '@chassis-ui/react'

// Freeze every item as `disabled` while the paginated data is fetching, so the paginator
// visibly reflects the loading state instead of accepting clicks that only queue up once the
// fetch resolves.
export const Example = () => {
  return (
    <Pagination aria-label="Page navigation example" aria-busy="true">
      <PaginationItem aria-label="Previous" disabled>
        &laquo;
      </PaginationItem>
      <PaginationItem active disabled>
        1
      </PaginationItem>
      <PaginationItem disabled>2</PaginationItem>
      <PaginationItem disabled>3</PaginationItem>
      <PaginationItem aria-label="Next" disabled>
        &raquo;
      </PaginationItem>
    </Pagination>
  )
}

Sizing

Set size to sm or lg to scale the page links and Prev/Next controls together.

JSX
import { useState } from 'react'
import { Pagination } from '@chassis-ui/react'

export const Example = () => {
  const [lgPage, setLargePage] = useState(2)
  const [smPage, setSmallPage] = useState(2)

  return (
    <>
      <Pagination
        size="lg"
        pages={3}
        activePage={lgPage}
        onActivePageChange={setLargePage}
        aria-label="Large pagination example"
      />
      <Pagination
        size="sm"
        pages={3}
        activePage={smPage}
        onActivePageChange={setSmallPage}
        aria-label="Small pagination example"
      />
    </>
  )
}

Alignment

Set align to center or end to position the pagination list within its container; the default is start-aligned.

JSX
import { useState } from 'react'
import { Pagination } from '@chassis-ui/react'

export const Example = () => {
  const [centerPage, setCenterPage] = useState(2)
  const [endPage, setEndPage] = useState(2)

  return (
    <>
      <Pagination
        align="center"
        pages={3}
        activePage={centerPage}
        onActivePageChange={setCenterPage}
        aria-label="Centered pagination"
      />
      <Pagination
        align="end"
        pages={3}
        activePage={endPage}
        onActivePageChange={setEndPage}
        aria-label="Right-aligned pagination"
      />
    </>
  )
}

API

Pagination

PropTypeDefault
activePage?number1
Current active page (1-indexed). Used with pages for data-driven mode.
align?"start" | "center" | "end"—
Set the alignment of pagination components.
aria-label?stringPagination
Accessible label for the pagination <nav> landmark. Override for non-English locales, or when multiple paginators appear on the same page.
className?string—
A string of all className you want applied to the base component.
maxVisiblePages?number5
Maximum number of visible page buttons (default: 5). Flanking pages are collapsed to ellipsis.
nextIcon?IconValue—
The "next page" control's icon in smart pagination mode: an icon name, or an element of your own icon set. Defaults to IconProvider's next icon.
nextLabel?stringNext
Accessible label for the "next page" control, used in smart pagination mode. Override for non-English locales.
onActivePageChange?((page: number) => void)—
Callback fired when the active page changes.
pages?number—
Total number of pages. When provided alongside activePage and onActivePageChange, the component renders a fully-controlled smart paginator with Prev/Next and ellipsis.
previousIcon?IconValue—
The "previous page" control's icon in smart pagination mode: an icon name, or an element of your own icon set. Defaults to IconProvider's previous icon.
previousLabel?stringPrevious
Accessible label for the "previous page" control, used in smart pagination mode. Override for non-English locales.
showPageNumbers?booleantrue
Show the numbered page buttons in smart pagination mode. Set false alongside showPrevNext to build a Prev/Next-only paginator.
showPrevNext?booleantrue
Show the Prev/Next controls in smart pagination mode. Set false alongside showPageNumbers to build a page-numbers-only paginator.
size?"sm" | "lg"—
Size the component sm or lg.

PaginationItem

PropTypeDefault
active?boolean—
Toggle the active state for the component.
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
disabled?boolean—
Toggle the disabled state for the component.
href?string—
The href attribute. When provided the item renders as an <a> tag; otherwise as a <button>.
ref?any—