Pagination

Alpha

Accessible pagination control. Renders a <nav> landmark with a labelled list of page buttons, optional First/Last buttons, an optional rows-per-page selector, and an optional Go to page input. Works fully controlled, fully uncontrolled, or mixed.

Import

import { Pagination } from "@compa11y/react";

Usage

Example.tsx
import { Pagination } from "@compa11y/react";

// Uncontrolled (simplest)
function BasicExample() {
  return <Pagination totalPages={24} />;
}

// Controlled
function ControlledExample() {
  const [page, setPage] = useState(1);
  return (
    <Pagination
      totalPages={24}
      currentPage={page}
      onPageChange={setPage}
    />
  );
}

// Derived from totalItems
function DerivedExample() {
  const [page, setPage] = useState(1);
  return (
    <Pagination
      totalItems={312}
      pageSize={25}
      currentPage={page}
      onPageChange={setPage}
    />
  );
}

// Full-featured
function FullExample() {
  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = useState(25);
  return (
    <Pagination
      totalItems={312}
      currentPage={page}
      onPageChange={setPage}
      showFirstLast
      showPageSize
      pageSizeOptions={[10, 25, 50, 100]}
      pageSize={pageSize}
      onPageSizeChange={setPageSize}
      showJumpTo
      ariaLabel="Products pagination"
    />
  );
}

// Disabled
function DisabledExample() {
  return <Pagination totalPages={10} currentPage={1} disabled />;
}

Features

  • <nav> landmark wraps all controls; aria-label defaults to "Pagination" and is customisable via ariaLabel
  • aria-current="page" on the active page button — no extra ARIA role needed
  • aria-label on every button: "Page N", "Previous page", "Next page", "First page", "Last page"
  • Native HTML disabled on buttons (not aria-disabled) for boundary and fully-disabled states
  • Live region (role="status" aria-live="polite") announces "Page N of M" on navigation and page-size changes
  • Ellipsis items carry aria-hidden="true" — purely visual
  • Rows-per-page <select> is labelled via htmlFor / id
  • Jump-to input uses aria-describedby for inline validation errors rendered in role="alert"
  • Stable IDs via useId — safe when multiple instances share a page
  • Controlled (currentPage / onPageChange), uncontrolled (defaultPage), and mixed modes
  • Dev warnings when neither totalPages nor totalItems is supplied, or currentPage is out of range

Props

Pagination component props
PropTypeDefaultDescription
totalPagesnumber-Total page count. Required unless totalItems is provided
totalItemsnumber-Total item count; used to derive totalPages when totalPages is not set
currentPagenumber-Controlled current page (1-indexed)
defaultPagenumber1Initial page for uncontrolled usage
onPageChange(page: number) => void-Called when the active page changes
ariaLabelstring"Pagination"aria-label for the <nav> landmark — must be unique when multiple instances appear on the same page
siblingCountnumber1Pages shown either side of the current page
boundaryCountnumber1Pages shown at each end of the range
showFirstLastbooleanfalseShow First (««) and Last (»») buttons
disabledbooleanfalseDisable all controls
unstyledbooleanfalseOmit data-compa11y-* attributes and inline layout styles
showPageSizebooleanfalseRender a rows-per-page <select>
pageSizenumber-Controlled page size
pageSizeOptionsnumber[][10, 25, 50]Options for the rows-per-page selector
onPageSizeChange(size: number) => void-Called when page size changes; component automatically resets to page 1
showJumpTobooleanfalseRender a "Go to page" number input

Keyboard Interactions

Accessibility
All keyboard interactions follow WAI-ARIA best practices and work without any additional configuration.
Keyboard shortcuts for Pagination
KeyAction
TabMoves between all controls in DOM order
Enter / SpaceNavigates to the focused page button
EnterSubmits the jump-to input; shows an inline error if the value is out of range

CSS Customization

Override these CSS custom properties to customize the appearance.

CSS custom properties for Pagination
VariableDescriptionDefault
--compa11y-pagination-colorButton text colorinherit
--compa11y-pagination-bgButton backgroundtransparent
--compa11y-pagination-borderButton border colorcurrentColor
--compa11y-pagination-radiusButton border radius4px
--compa11y-pagination-sizeMinimum button width and height (touch target)44px
--compa11y-pagination-current-bgCurrent page button backgroundcurrentColor
--compa11y-pagination-current-colorCurrent page button text colorcanvas
--compa11y-focus-colorFocus ring color#0066cc