Component
Pagination
Muted Previous and Next with carets around ink page numbers; the current page is a white key with Shadow/S.
npx -y github:anwarlemu/inkbox-brand-cli#release add paginationUsage
Use under a table or list that has more than one page. Pass bar to set it in the lilac bar that sits 8px under a table, as the console does. Mark the current page with isActive and disable Previous on the first page with aria-disabled.
Avoid
- A purple current page
- Page numbers in the action purple
- More than seven page links at once
Exports: Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious. Read the examples for composition and props.
Dependencies: @phosphor-icons/react.
Example
import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";export function Preview() { return ( <Pagination bar> <PaginationContent> <PaginationItem> <PaginationPrevious href="#" aria-disabled /> </PaginationItem> <PaginationItem> <PaginationLink href="#" isActive> 1 </PaginationLink> </PaginationItem> <PaginationItem> <PaginationLink href="#">2</PaginationLink> </PaginationItem> <PaginationItem> <PaginationNext href="#" /> </PaginationItem> </PaginationContent> </Pagination> );}export function Plain() { return ( <Pagination> <PaginationContent> <PaginationItem> <PaginationPrevious href="#" /> </PaginationItem> <PaginationItem> <PaginationLink href="#">1</PaginationLink> </PaginationItem> <PaginationItem> <PaginationEllipsis /> </PaginationItem> <PaginationItem> <PaginationLink href="#">7</PaginationLink> </PaginationItem> <PaginationItem> <PaginationLink href="#" isActive> 8 </PaginationLink> </PaginationItem> <PaginationItem> <PaginationLink href="#">9</PaginationLink> </PaginationItem> <PaginationItem> <PaginationEllipsis /> </PaginationItem> <PaginationItem> <PaginationLink href="#">24</PaginationLink> </PaginationItem> <PaginationItem> <PaginationNext href="#" /> </PaginationItem> </PaginationContent> </Pagination> );}Source
import * as React from "react";import { CaretLeftIcon, CaretRightIcon, DotsThreeIcon } from "@phosphor-icons/react/ssr";import { cn } from "@/lib/utils";// The console's pagination (Figma 427:2715, under the Email and iMessage tables): 14px muted "Previous" and "Next" with// 16px carets, the page numbers in 14px ink, and the current page a 40 by 30 white key with 8px corners and Shadow/S.// `bar` sets it in the 42px lilac bar with 10px corners that sits 8px under a table, the pages at its right end.function Pagination({ className, bar = false, ...props }: React.ComponentProps<"nav"> & { bar?: boolean }) { return ( <nav role="navigation" aria-label="pagination" data-slot="pagination" data-bar={bar || undefined} className={cn("flex w-full justify-center", bar && "min-h-10.5 items-center justify-end rounded-panel bg-subtle px-2 py-1.5", className)} {...props} /> );}function PaginationContent({ className, ...props }: React.ComponentProps<"ul">) { return <ul data-slot="pagination-content" className={cn("flex flex-row flex-wrap items-center gap-1", className)} {...props} />;}function PaginationItem(props: React.ComponentProps<"li">) { return <li data-slot="pagination-item" {...props} />;}type PaginationLinkProps = { isActive?: boolean; size?: "icon" | "default" } & React.ComponentProps<"a">;const LINK = "inline-flex h-7.5 shrink-0 items-center justify-center gap-1 rounded-control font-sans text-body leading-tight whitespace-nowrap outline-none transition-[background-color,color,box-shadow,scale] duration-150 ease-out active:scale-97 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 motion-reduce:transition-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4";function PaginationLink({ className, isActive, size = "icon", ...props }: PaginationLinkProps) { return ( <a aria-current={isActive ? "page" : undefined} data-slot="pagination-link" data-active={isActive || undefined} className={cn( LINK, size === "icon" ? "min-w-10 px-2" : "px-2.5", isActive ? "bg-surface text-fg shadow-s" : "text-fg hover:bg-subtle-hover in-data-[bar=true]:hover:bg-surface/70", className, )} {...props} /> );}function PaginationPrevious({ className, children = "Previous", ...props }: React.ComponentProps<typeof PaginationLink>) { return ( <PaginationLink aria-label="Go to previous page" size="default" className={cn("text-fg-muted hover:text-fg", className)} {...props}> <CaretLeftIcon aria-hidden /> <span>{children}</span> </PaginationLink> );}function PaginationNext({ className, children = "Next", ...props }: React.ComponentProps<typeof PaginationLink>) { return ( <PaginationLink aria-label="Go to next page" size="default" className={cn("text-fg-muted hover:text-fg", className)} {...props}> <span>{children}</span> <CaretRightIcon aria-hidden /> </PaginationLink> );}function PaginationEllipsis({ className, ...props }: React.ComponentProps<"span">) { return ( <span aria-hidden data-slot="pagination-ellipsis" className={cn("flex h-7.5 min-w-8 items-center justify-center text-fg-muted", className)} {...props}> <DotsThreeIcon weight="bold" className="size-4" /> <span className="sr-only">More pages</span> </span> );}export { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious };Reference: Figma 427:2715: the pagination bar under the Email and iMessage tables.