Pagination with page navigation, next and previous links.
Installation
npx shadcn@latest add @caprice/paginationnpm install @caprice-ui/reactInstall the following dependencies:
npm install @base-ui/react lucide-reactAdd a cn helper
import { defineConfig, type VariantProps } from 'cva';import { twMerge } from 'tailwind-merge';export const { compose, cva, cx: cn,} = defineConfig({ hooks: { onComplete: (className: string) => twMerge(className), },});export type { VariantProps };Copy and paste the following code into your project.
'use client';import { mergeProps, useRender } from '@base-ui/react';import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from 'lucide-react';import type * as React from 'react';import { type Button, buttonVariants } from '@/components/caprice-ui/button';import { cn } from '@/lib/utils';/** * Groups the pagination content. * Renders a `<nav>` element. * * Documentation: [Caprice UI Pagination](https://caprice-ui.com/docs/components/pagination) */export namespace Root { export type Props = React.ComponentProps<'nav'>;}export function Root({ className, ...props }: Root.Props) { return ( <nav aria-label="pagination" className={cn('mx-auto flex w-full justify-center', className)} data-slot="pagination" {...props} /> );}/** * A container for the pagination items. * Renders a `<ul>` element. * * Documentation: [Caprice UI Pagination](https://caprice-ui.com/docs/components/pagination) */export namespace Content { export type Props = React.ComponentProps<'ul'>;}export function Content({ className, ...props }: Content.Props) { return ( <ul className={cn('flex flex-row items-center gap-1', className)} data-slot="pagination-content" {...props} /> );}/** * An individual pagination item. * Renders a `<li>` element. * * Documentation: [Caprice UI Pagination](https://caprice-ui.com/docs/components/pagination) */export namespace Item { export type Props = React.ComponentProps<'li'>;}export function Item({ ...props }: Item.Props) { return <li data-slot="pagination-item" {...props} />;}/** * A link component. * Renders an `<a>` element. * * Documentation: [Caprice UI Pagination](https://caprice-ui.com/docs/components/pagination) */export namespace Link { export type Props = useRender.ComponentProps<'a'> & Pick<Button.Props, 'size'> & { /** * Whether the link is active. * @default false */ isActive?: boolean; };}export function Link({ className, render, isActive, size = 'icon', ...props }: Link.Props) { const defaultProps: useRender.ElementProps<'a'> & { 'data-slot'?: string } = { 'data-slot': 'pagination-link', className: cn( buttonVariants({ variant: isActive ? 'outline' : 'ghost', size, }), className ), }; return useRender({ defaultTagName: 'a', render, state: { active: isActive, }, stateAttributesMapping: { active: (value) => (value ? { 'aria-current': 'page' } : null), }, props: mergeProps<'a'>(defaultProps, props), });}/** * The previous page link. * Renders a {@link Link} component. * * Documentation: [Caprice UI Pagination](https://caprice-ui.com/docs/components/pagination) */export namespace Previous { export type Props = React.ComponentProps<typeof Link>;}export function Previous({ className, ...props }: Previous.Props) { return ( <Link aria-label="Go to previous page" className={cn('gap-1 px-2.5 sm:pl-2.5', className)} size="md" {...props} > <ChevronLeftIcon /> <span className="hidden sm:block">Previous</span> </Link> );}/** * The next page link. * Renders a {@link Link} component. * * Documentation: [Caprice UI Pagination](https://caprice-ui.com/docs/components/pagination) */export namespace Next { export type Props = React.ComponentProps<typeof Link>;}export function Next({ className, ...props }: Next.Props) { return ( <Link aria-label="Go to next page" className={cn('gap-1 px-2.5 sm:pr-2.5', className)} size="md" {...props} > <span className="hidden sm:block">Next</span> <ChevronRightIcon /> </Link> );}/** * An ellipsis component. * Renders a `<span>` element. * * Documentation: [Caprice UI Pagination](https://caprice-ui.com/docs/components/pagination) */export namespace Ellipsis { export type Props = React.ComponentProps<'span'>;}export function Ellipsis({ className, ...props }: Ellipsis.Props) { return ( <span aria-hidden className={cn('flex size-9 items-center justify-center', className)} data-slot="pagination-ellipsis" {...props} > <MoreHorizontalIcon className="size-4" /> <span className="sr-only">More pages</span> </span> );}Update the import paths to match your project setup.
Usage
import * as Pagination from "@/components/caprice-ui/pagination"import * as Pagination from "@caprice-ui/react/pagination"<Pagination.Root>
<Pagination.Content>
<Pagination.Item>
<PaginationPrevious href="#" />
</Pagination.Item>
<Pagination.Item>
<PaginationLink href="#">1</PaginationLink>
</Pagination.Item>
<Pagination.Item>
<Pagination.Ellipsis />
</Pagination.Item>
<Pagination.Item>
<Pagination.Next href="#" />
</Pagination.Item>
</Pagination.Content>
</Pagination.Root>Custom Link
By default the <Pagination.Link /> component will render an tag, you can customize the link by passing a render prop.
import Link from 'next/link';
<Pagination.Root>
<Pagination.Content>
<Pagination.Item>
<Pagination.Link render={<Link href="#" />} />
</Pagination.Item>
</Pagination.Content>
</Pagination.Root>