Pagination

Page navigation controls with numbered pages, previous/next buttons, ellipsis gaps, active page indicator, and disabled state support.

Preview

Basic pagination

import { Pagination, PaginationPrevious, PaginationNext, PaginationList, PaginationPage } from '@/registry/ui-kit/tailwind-pagination/react'

function Example() {
  return (
    <Pagination>
      <PaginationPrevious href="#" />
      <PaginationList>
        <PaginationPage href="#">1</PaginationPage>
        <PaginationPage href="#">2</PaginationPage>
        <PaginationPage current href="#">3</PaginationPage>
        <PaginationPage href="#">4</PaginationPage>
        <PaginationPage href="#">5</PaginationPage>
      </PaginationList>
      <PaginationNext href="#" />
    </Pagination>
  )
}

With gap

import { Pagination, PaginationPrevious, PaginationNext, PaginationList, PaginationPage, PaginationGap } from '@/registry/ui-kit/tailwind-pagination/react'

function Example() {
  return (
    <Pagination>
      <PaginationPrevious href="#" />
      <PaginationList>
        <PaginationPage href="#">1</PaginationPage>
        <PaginationPage current href="#">2</PaginationPage>
        <PaginationPage href="#">3</PaginationPage>
        <PaginationGap />
        <PaginationPage href="#">10</PaginationPage>
      </PaginationList>
      <PaginationNext href="#" />
    </Pagination>
  )
}

Disabled navigation

import { Pagination, PaginationPrevious, PaginationNext, PaginationList, PaginationPage } from '@/registry/ui-kit/tailwind-pagination/react'

function Example() {
  return (
    <Pagination>
      <PaginationPrevious disabled />
      <PaginationList>
        <PaginationPage current href="#">1</PaginationPage>
        <PaginationPage href="#">2</PaginationPage>
        <PaginationPage href="#">3</PaginationPage>
      </PaginationList>
      <PaginationNext disabled />
    </Pagination>
  )
}

Component API

PropDefaultDescription
PaginationWrapper nav element with flex layout.
PaginationPreviousPrevious page button with left arrow SVG. Accepts disabled prop.
PaginationNextNext page button with right arrow SVG. Accepts disabled prop.
PaginationListContainer for page number buttons.
PaginationPagePage number link. Accepts current boolean and href.
currentfalseHighlights the page as the active page with indigo background.
disabledfalseDisables prev/next buttons with reduced opacity.
PaginationGapRenders an ellipsis to indicate skipped pages.

Source Code

"use client";

/* ── Base button styles ── */

const baseStyles =
  "inline-flex h-9 min-w-9 items-center justify-center rounded-lg px-3 text-sm font-medium transition-colors";
const currentStyles = "bg-indigo-600 text-white";
const defaultStyles =
  "text-zinc-500 hover:bg-zinc-100 dark:text-zinc-400 dark:hover:bg-zinc-800";
const disabledStyles = "opacity-50 cursor-not-allowed";

/* ── Pagination ── */

interface PaginationProps {
  children: React.ReactNode;
  className?: string;
}

function Pagination({ children, className = "" }: PaginationProps) {
  return (
    <nav
      aria-label="Pagination"
      className={`flex items-center gap-1 ${className}`}
    >
      {children}
    </nav>
  );
}

/* ── PaginationPrevious ── */

interface PaginationPreviousProps
  extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
  disabled?: boolean;
  className?: string;
}

function PaginationPrevious({
  disabled = false,
  className = "",
  ...props
}: PaginationPreviousProps) {
  const Tag = disabled ? "span" : "a";
  return (
    <Tag
      className={`${baseStyles} ${disabled ? disabledStyles : defaultStyles} ${className}`}
      aria-label="Previous page"
      aria-disabled={disabled || undefined}
      {...(disabled ? {} : props)}
    >
      <svg
        className="h-4 w-4"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
        strokeLinecap="round"
        strokeLinejoin="round"
      >
        <path d="m15 18-6-6 6-6" />
      </svg>
    </Tag>
  );
}

/* ── PaginationNext ── */

interface PaginationNextProps
  extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
  disabled?: boolean;
  className?: string;
}

function PaginationNext({
  disabled = false,
  className = "",
  ...props
}: PaginationNextProps) {
  const Tag = disabled ? "span" : "a";
  return (
    <Tag
      className={`${baseStyles} ${disabled ? disabledStyles : defaultStyles} ${className}`}
      aria-label="Next page"
      aria-disabled={disabled || undefined}
      {...(disabled ? {} : props)}
    >
      <svg
        className="h-4 w-4"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
        strokeLinecap="round"
        strokeLinejoin="round"
      >
        <path d="m9 18 6-6-6-6" />
      </svg>
    </Tag>
  );
}

/* ── PaginationList ── */

interface PaginationListProps {
  children: React.ReactNode;
  className?: string;
}

function PaginationList({ children, className = "" }: PaginationListProps) {
  return (
    <span className={`flex items-center gap-1 ${className}`}>{children}</span>
  );
}

/* ── PaginationPage ── */

interface PaginationPageProps
  extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
  current?: boolean;
  className?: string;
  children: React.ReactNode;
}

function PaginationPage({
  current = false,
  children,
  className = "",
  ...props
}: PaginationPageProps) {
  return (
    <a
      className={`${baseStyles} ${current ? currentStyles : defaultStyles} ${className}`}
      aria-current={current ? "page" : undefined}
      {...props}
    >
      {children}
    </a>
  );
}

/* ── PaginationGap ── */

interface PaginationGapProps {
  className?: string;
}

function PaginationGap({ className = "" }: PaginationGapProps) {
  return (
    <span
      className={`${baseStyles} text-zinc-400 dark:text-zinc-500 ${className}`}
      aria-hidden="true"
    >
      &hellip;
    </span>
  );
}

export {
  Pagination,
  PaginationPrevious,
  PaginationNext,
  PaginationList,
  PaginationPage,
  PaginationGap,
};
export default Pagination;