Navigation

Pagination.

Page links with previous and next controls. The current page gets an orange outline.

Installation#

With the CLI

$npx lanterncn add pagination

This also installs the Lantern theme and any Lantern UI components it depends on. The shadcn CLI works directly too: npx shadcn@latest add httptim/lantern-ui/pagination. See Installation if your project is not set up yet.

Manually

  1. Install the dependencies

    npm install lucide-react
  2. Copy the source into your project

    components/ui/pagination.tsx
    import * as React from "react";
    import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
    
    import { cn } from "@/lib/utils";
    import { buttonVariants, type Button } from "@/components/ui/button";
    
    function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
      return (
        <nav
          role="navigation"
          aria-label="pagination"
          data-slot="pagination"
          className={cn("mx-auto flex w-full justify-center", className)}
          {...props}
        />
      );
    }
    
    function PaginationContent({ className, ...props }: React.ComponentProps<"ul">) {
      return <ul data-slot="pagination-content" className={cn("flex flex-row items-center gap-1", className)} {...props} />;
    }
    
    function PaginationItem({ ...props }: React.ComponentProps<"li">) {
      return <li data-slot="pagination-item" {...props} />;
    }
    
    type PaginationLinkProps = {
      isActive?: boolean;
    } & Pick<React.ComponentProps<typeof Button>, "size"> &
      React.ComponentProps<"a">;
    
    function PaginationLink({ className, isActive, size = "icon-sm", ...props }: PaginationLinkProps) {
      return (
        <a
          aria-current={isActive ? "page" : undefined}
          data-slot="pagination-link"
          data-active={isActive}
          className={cn(
            buttonVariants({ variant: isActive ? "outline" : "ghost", size }),
            "font-mono text-xs font-medium tabular-nums active:translate-y-0",
            isActive && "border-primary text-primary hover:bg-primary/10",
            className,
          )}
          {...props}
        />
      );
    }
    
    function PaginationPrevious({ className, ...props }: React.ComponentProps<typeof PaginationLink>) {
      return (
        <PaginationLink
          aria-label="Go to previous page"
          size="sm"
          className={cn("gap-1.5 px-2.5 text-[11px] tracking-[0.14em] uppercase sm:pl-2", className)}
          {...props}
        >
          <ChevronLeftIcon />
          <span className="hidden sm:block">Prev</span>
        </PaginationLink>
      );
    }
    
    function PaginationNext({ className, ...props }: React.ComponentProps<typeof PaginationLink>) {
      return (
        <PaginationLink
          aria-label="Go to next page"
          size="sm"
          className={cn("gap-1.5 px-2.5 text-[11px] tracking-[0.14em] uppercase sm:pr-2", className)}
          {...props}
        >
          <span className="hidden sm:block">Next</span>
          <ChevronRightIcon />
        </PaginationLink>
      );
    }
    
    function PaginationEllipsis({ className, ...props }: React.ComponentProps<"span">) {
      return (
        <span
          aria-hidden
          data-slot="pagination-ellipsis"
          className={cn("flex size-8 items-center justify-center text-muted-foreground", className)}
          {...props}
        >
          <MoreHorizontalIcon className="size-4" />
          <span className="sr-only">More pages</span>
        </span>
      );
    }
    
    export {
      Pagination,
      PaginationContent,
      PaginationEllipsis,
      PaginationItem,
      PaginationLink,
      PaginationNext,
      PaginationPrevious,
    };
  3. Update the import paths to match your project

    The source imports cn from @/lib/utils and uses button.

Usage#

import {
  Pagination,
  PaginationContent,
  PaginationEllipsis,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "@/components/ui/pagination";
<Pagination>
  <PaginationContent>
    <PaginationItem><PaginationPrevious href="#" /></PaginationItem>
    <PaginationItem><PaginationLink href="#" isActive>2</PaginationLink></PaginationItem>
    <PaginationItem><PaginationNext href="#" /></PaginationItem>
  </PaginationContent>
</Pagination>

The Prev and Next words hide on phones to leave room for the page numbers.