codefast/ui

Command Palette

Search for a command to run...

Source
Navigation

Pagination

Page navigation with prev/next, ellipsis, and active page. Compose with your router.

Examples

Simple

Static markup with an active page and prev / next.

27 lines
import { Pagination, PaginationContent, PaginationItem, PaginationLink } from "@codefast/ui/pagination";

export function PaginationSimple() {
  return (
    <Pagination>
      <PaginationContent>
        <PaginationItem>
          <PaginationLink href="#">1</PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationLink href="#" isActive>
            2
          </PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationLink href="#">3</PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationLink href="#">4</PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationLink href="#">5</PaginationLink>
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  );
}

Icons Only

Use just the previous and next buttons without page numbers. This is useful for data tables with a rows per page selector.

42 lines
import { Field, FieldLabel } from "@codefast/ui/field";
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationNext,
  PaginationPrevious,
} from "@codefast/ui/pagination";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@codefast/ui/select";

export function PaginationIconsOnly() {
  return (
    <div className="flex items-center justify-between gap-4">
      <Field orientation="horizontal" className="w-fit">
        <FieldLabel htmlFor="select-rows-per-page">Rows per page</FieldLabel>
        <Select defaultValue="25">
          <SelectTrigger className="w-20" id="select-rows-per-page">
            <SelectValue />
          </SelectTrigger>
          <SelectContent align="start">
            <SelectGroup>
              <SelectItem value="10">10</SelectItem>
              <SelectItem value="25">25</SelectItem>
              <SelectItem value="50">50</SelectItem>
              <SelectItem value="100">100</SelectItem>
            </SelectGroup>
          </SelectContent>
        </Select>
      </Field>
      <Pagination className="mx-0 w-auto">
        <PaginationContent>
          <PaginationItem>
            <PaginationPrevious href="#" />
          </PaginationItem>
          <PaginationItem>
            <PaginationNext href="#" />
          </PaginationItem>
        </PaginationContent>
      </Pagination>
    </div>
  );
}

RTL

Right-to-left layout support for languages such as Arabic and Hebrew.

Translations are AI-generated for demonstration and may be imperfect.

83 lines
import {
  Pagination,
  PaginationContent,
  PaginationEllipsis,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "@codefast/ui/pagination";

import type { Translations } from "#/features/components-catalog/components/detail/language";
import { useTranslation } from "#/features/components-catalog/components/detail/language-context";

const translations: Translations = {
  en: {
    dir: "ltr",
    values: {
      previous: "Previous",
      next: "Next",
    },
  },
  ar: {
    dir: "rtl",
    values: {
      previous: "السابق",
      next: "التالي",
    },
  },
  he: {
    dir: "rtl",
    values: {
      previous: "הקודם",
      next: "הבא",
    },
  },
};

function toArabicNumerals(num: number): string {
  const arabicNumerals = ["٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"];
  return num
    .toString()
    .split("")
    .map((digit) => arabicNumerals[parseInt(digit, 10)])
    .join("");
}

export function PaginationRtl() {
  const { dir, t, language } = useTranslation(translations, "ar");

  const formatNumber = (num: number): string => {
    if (language === "ar") {
      return toArabicNumerals(num);
    }
    return num.toString();
  };

  return (
    <Pagination dir={dir}>
      <PaginationContent>
        <PaginationItem>
          <PaginationPrevious href="#" text={t.previous ?? "Previous"} />
        </PaginationItem>
        <PaginationItem>
          <PaginationLink href="#">{formatNumber(1)}</PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationLink href="#" isActive>
            {formatNumber(2)}
          </PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationLink href="#">{formatNumber(3)}</PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationEllipsis />
        </PaginationItem>
        <PaginationItem>
          <PaginationNext href="#" text={t.next ?? "Next"} />
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  );
}

Anatomy

How the parts nest — every slot the component exposes, in composition order.

Pagination
└── PaginationContent
├── PaginationItem
│ └── PaginationPrevious
├── PaginationItem
│ └── PaginationLink
├── PaginationItem
│ └── PaginationEllipsis
└── PaginationItem
└── PaginationNext

Features

  • Every part is a plain <a>/<li>/<nav> — wire onClick/href to your router or state yourself; there's no built-in page-state management.
  • PaginationLink's isActive swaps between outline (current page) and ghost (other pages) Button variants automatically.
  • PaginationPrevious/PaginationNext hide their text label below the sm breakpoint, leaving just the chevron icon.

API reference

Props for each part of the component. All native element props are also forwarded.

PaginationLink

A page link. Compose your own paginator; wire it to your router or state.

isActiveboolean

Marks the current page — swaps to the outline Button variant.

PaginationPrevious

The previous-page control — disable at the lower bound via class + aria-disabled.

textstring

The label shown above the sm breakpoint.

Default"Previous"

PaginationNext

The next-page control — disable at the upper bound via class + aria-disabled.

textstring

The label shown above the sm breakpoint.

Default"Next"

PaginationEllipsis

A non-interactive gap marker for skipped pages. Renders a fixed MoreHorizontal icon.

classNamestring

Compose additional classes onto the span.

Accessibility

Built to be keyboard-navigable and screen-reader friendly out of the box.

  • Renders a nav landmark labelled “pagination”.
  • Mark the current page link with aria-current="page".
  • Communicate disabled prev/next with aria-disabled, not just opacity.

Guidelines

Conventions that keep usage consistent across an app.

Do

  • Show first, last, current, and neighbours; collapse the rest with an ellipsis.
  • Keep the active page clearly highlighted.

Don’t

  • Don’t render dozens of page links — window them.
  • Don’t leave prev/next clickable at the bounds.

Explore further

Ready to integrate?

Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.