Pagination
Navigation controls for splitting multi-page content into discrete pages with stateful switching, icon modes, and first/last jump controls.
pagination.tsx
Pagination bar component supporting page switching, previous/next/first/last controls, and page ellipsis.
ReactTailwindUI ComponentNavigationPagination
"use client";
import * as React from "react";
import { Icon } from "@iconify/react";
import { cn } from "@/lib/utils";
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
<nav
role="navigation"
aria-label="pagination"
className={cn("mx-auto flex w-full justify-center", className)}
{...props}
/>
);
Pagination.displayName = "Pagination";
const PaginationContent = React.forwardRef<
HTMLUListElement,
React.ComponentProps<"ul">
>(({ className, ...props }, ref) => (
<ul
ref={ref}
className={cn("flex flex-wrap items-center gap-1.5", className)}
{...props}
/>
));
PaginationContent.displayName = "PaginationContent";
const PaginationItem = React.forwardRef<
HTMLLIElement,
React.ComponentProps<"li">
>(({ className, ...props }, ref) => (
<li ref={ref} className={cn("", className)} {...props} />
));
PaginationItem.displayName = "PaginationItem";
export interface PaginationLinkProps extends React.ComponentProps<"button"> {
isActive?: boolean;
size?: "sm" | "md" | "lg";
}
const PaginationLink = ({
className,
isActive,
size = "md",
onClick,
children,
...props
}: PaginationLinkProps) => {
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
if (onClick) onClick(e);
};
return (
<button
type="button"
data-active={isActive}
aria-current={isActive ? "page" : undefined}
onClick={handleClick}
className={cn(
"inline-flex items-center justify-center rounded-xl border border-border bg-card font-medium transition-all duration-200 cursor-pointer select-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
size === "sm" && "h-8 min-w-8 text-xs px-2.5",
size === "md" && "h-9 min-w-9 text-sm px-3",
size === "lg" && "h-10 min-w-10 text-base px-3.5",
isActive
? "border-primary bg-primary text-primary-foreground font-semibold shadow-xs"
: "text-foreground hover:bg-accent hover:text-accent-foreground",
className
)}
{...props}
>
{children}
</button>
);
};
PaginationLink.displayName = "PaginationLink";
const PaginationFirst = ({
className,
label,
...props
}: React.ComponentProps<typeof PaginationLink> & { label?: string }) => (
<PaginationLink
aria-label="Go to first page"
className={cn("gap-1 px-2.5", className)}
{...props}
>
<Icon icon="hugeicons:arrow-left-double" className="size-4" />
{label && <span>{label}</span>}
</PaginationLink>
);
PaginationFirst.displayName = "PaginationFirst";
const PaginationLast = ({
className,
label,
...props
}: React.ComponentProps<typeof PaginationLink> & { label?: string }) => (
<PaginationLink
aria-label="Go to last page"
className={cn("gap-1 px-2.5", className)}
{...props}
>
{label && <span>{label}</span>}
<Icon icon="hugeicons:arrow-right-double" className="size-4" />
</PaginationLink>
);
PaginationLast.displayName = "PaginationLast";
const PaginationPrevious = ({
className,
label = "Previous",
...props
}: React.ComponentProps<typeof PaginationLink> & { label?: string }) => (
<PaginationLink
aria-label="Go to previous page"
className={cn("gap-1.5 pl-2.5", className)}
{...props}
>
<Icon icon="hugeicons:arrow-left-01" className="size-4" />
{label && <span>{label}</span>}
</PaginationLink>
);
PaginationPrevious.displayName = "PaginationPrevious";
const PaginationNext = ({
className,
label = "Next",
...props
}: React.ComponentProps<typeof PaginationLink> & { label?: string }) => (
<PaginationLink
aria-label="Go to next page"
className={cn("gap-1.5 pr-2.5", className)}
{...props}
>
{label && <span>{label}</span>}
<Icon icon="hugeicons:arrow-right-01" className="size-4" />
</PaginationLink>
);
PaginationNext.displayName = "PaginationNext";
const PaginationEllipsis = ({
className,
...props
}: React.ComponentProps<"span">) => (
<span
aria-hidden
className={cn("flex size-9 items-center justify-center text-muted-foreground", className)}
{...props}
>
<Icon icon="hugeicons:more-horizontal" className="size-4" />
<span className="sr-only">More pages</span>
</span>
);
PaginationEllipsis.displayName = "PaginationEllipsis";
export {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
PaginationFirst,
PaginationLast,
};
Interactive Stateful Page Switching
Stateful page switching that updates content dynamically without anchor jump scroll.
Active Page: 1 of 5
First & Last Controls
Include PaginationFirst and PaginationLast buttons to jump directly to the beginning or end of large datasets.
Active Page: 12 of 20
Compact Icon-Only Mode
Pass label='' to hide text labels for a compact icon-driven pagination layout.
Active Page: 2 of 5
API Reference
Props — Pagination
Sub-components for composing accessible Pagination controls.
| Component | Props | Description |
|---|---|---|
| Pagination | HTMLNavProps | Root container with role="navigation". |
| PaginationLink | isActive?: boolean, size?: 'sm'|'md'|'lg' | Interactive page button with active indicator state. |
| PaginationFirst / PaginationLast | label?: string | Buttons to jump directly to page 1 or the last page. |
| PaginationPrevious / PaginationNext | label?: string | Previous and Next page navigation buttons. |