Skip to Content
ComponentsPagination

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; };
Last updated on