Skip to main content

Pagination

The Pagination component provides a compact page navigation UI (Prev/Next + page numbers + optional placeholders) and works well with controlled state.


Props

NameTypeDefaultProvider?Description
pagenumber1NoCurrent page (1-based).
totalPagesnumberNoTotal number of pages. If < 1, the component renders nothing.
onChange(page: number) => voidNoCalled when the user changes page (Prev/Next or clicking a page number).
seblingsnumber1YesHow many pages to show around the current page.
disabledbooleanNoDisables all buttons and prevents navigation.
placeholderIconReactNode"..."YesCustom icon/content for placeholder buttons.
prevIconReactNode"Prev"YesCustom icon/content for the previous button.
nextIconReactNode"Next"YesCustom icon/content for the next button.

Note Props marked with Yes in the Provider? column can be configured globally using the ComponentPropsProvider.


Usage

Quick start

import React, { useState } from "react";
import { Pagination } from "@kousta-ui/components";

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

return (
  <div style={{ width: "100%" }}>
    <Pagination page={page} totalPages={10} onChange={setPage} />
  </div>
);
}

seblings

Use seblings to show more pages around the current page.

import React, { useState } from "react";
import { Pagination } from "@kousta-ui/components";

export function Example() {
const [page, setPage] = useState(10);

return (
  <div style={{ width: "100%" }}>
    <Pagination page={page} totalPages={20} onChange={setPage} seblings={2} />
  </div>
);
}

Disabled

import { Pagination } from "@kousta-ui/components";

export function Example() {
return (
  <div style={{ width: "100%" }}>
    <Pagination page={1} totalPages={10} disabled />
  </div>
);
}

Icons

You can override the built-in content of the control buttons and placeholders.

Override icons on a single Pagination

import React, { useState } from "react";
import { Pagination } from "@kousta-ui/components";
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";

export function Example() {
const [page, setPage] = useState(6);

return (
  <div style={{ width: "100%" }}>
    <Pagination
      page={page}
      totalPages={20}
      onChange={setPage}
      prevIcon={<ChevronLeft size={16} />}
      nextIcon={<ChevronRight size={16} />}
      placeholderIcon={<MoreHorizontal size={16} />}
      seblings={1}
    />
  </div>
);
}

Override icons with ComponentPropsProvider

import React, { useState } from "react";
import { ComponentPropsProvider, Pagination } from "@kousta-ui/components";
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";

export function Example() {
const [page, setPage] = useState(6);

return (
  <ComponentPropsProvider
    pagination={{
      prevIcon: <ChevronLeft size={16} />,
      nextIcon: <ChevronRight size={16} />,
      placeholderIcon: <MoreHorizontal size={16} />,
      seblings: 1,
    }}
  >
    <div style={{ width: "100%" }}>
      <Pagination page={page} totalPages={20} onChange={setPage} />
    </div>
  </ComponentPropsProvider>
);
}

With usePagination

If you want the logic (total pages, boundaries, setters) handled for you, use the usePagination hook.

import { Pagination } from "@kousta-ui/components";
import { usePagination } from "@kousta-ui/hooks";

export function Example() {
const { page, totalPages, setPage } = usePagination({ total: 240, limit: 20 });

return (
  <div style={{ width: "100%" }}>
    <Pagination page={page} totalPages={totalPages} onChange={setPage} />
  </div>
);
}

Code review

  • Controlled vs internal state: Pagination keeps an internal currentPage state for UI, and syncs it when the page prop changes.
  • Boundaries: Prev/Next are disabled at 1 and totalPages (and everything is disabled when disabled is true).
  • Page calculation: The component uses seblings and the getSeblings helper to compute which page numbers to show. It inserts placeholders ("") which render as disabled buttons showing placeholderIcon (or "...").
  • Provider overrides: ComponentPropsProvider can override placeholderIcon, nextIcon, prevIcon, and seblings. Local props win when provided.

Accessibility

  • Labels: Provide accessible labels for icon-only pagination controls (for example via prevIcon / nextIcon content or by wrapping with aria-label at the button level if you override rendering).
  • Current page: Ensure the active page is clearly indicated visually (the component applies kui-pagination-active-link).
  • Keyboard: Pagination controls are buttons/links and are keyboard reachable by default; test Tab order when embedding in complex toolbars.

Styles & customization

Runtime classes

  • kui-pagination-link: Applied to all clickable controls (Prev/Next + page buttons).
  • kui-pagination-active-link: Applied to the active page.
  • kui-pagination-placeholder: Applied to placeholder buttons.

Types (reference)

import { ReactNode } from "react";

export type PaginationProps = {
page: number;
onChange?: (page: number) => void;
totalPages: number;
seblings?: number;
disabled?: boolean;

placeholderIcon?: ReactNode;
nextIcon?: ReactNode;
prevIcon?: ReactNode;
};