CoreUI is in beta - APIs and components may change.
CoreUI
Base Components

Pagination

Pagination is a horizontal set of links to navigate paginated content.


Coming from Figma

In Figma the Pagination uses Type (Basic / Group / Full Radius) plus First / Last and Next / Previous controls. In code:

  • Type: the variant prop on Pagination.Root: basic, group, and rounded (Figma's "Full Radius").
  • First / Last, Next / Previous: add Pagination.NavButton with the appropriate Pagination.NavIcon (e.g. a double-arrow icon for first/last).
  • Current page: the current prop on Pagination.Item.

Installation

Install the following dependencies:

npm install @radix-ui/react-slot

Create a pagination.tsx file and paste the following code into it.

components/ui/pagination.tsx
// CoreUI Pagination v0.0.0import * as React from 'react';import { Slot } from '@radix-ui/react-slot';import { cn } from '@/utils/cn';import type { PolymorphicComponentProps } from '@/utils/polymorphic';import { recursiveCloneChildren } from '@/utils/recursive-clone-children';import { tv, type VariantProps } from '@/utils/tv';const PAGINATION_ROOT_NAME = 'PaginationRoot';const PAGINATION_ITEM_NAME = 'PaginationItem';const PAGINATION_NAV_BUTTON_NAME = 'PaginationNavButton';const PAGINATION_NAV_ICON_NAME = 'PaginationNavIcon';const paginationVariants = tv({  slots: {    root: 'flex flex-wrap items-center justify-center',    item: 'flex items-center justify-center text-center text-label-sm text-text-sub-600 transition duration-200 ease-out',    navButton:      'flex items-center justify-center text-text-sub-600 transition duration-200 ease-out',    navIcon: 'size-5',  },  variants: {    variant: {      basic: {        root: 'gap-2',        item: [          // base          'h-8 min-w-8 rounded-lg px-1.5 ring-1 ring-inset ring-stroke-soft-200',          // hover          'hover:bg-bg-weak-50 hover:ring-transparent',        ],        navButton: [          // base          'size-8 rounded-lg',          // hover          'hover:bg-bg-weak-50',        ],      },      rounded: {        root: 'gap-2',        item: [          // base          'h-8 min-w-8 rounded-full px-1.5 ring-1 ring-inset ring-stroke-soft-200',          // hover          'hover:bg-bg-weak-50 hover:ring-transparent',        ],        navButton: [          // base          'size-8 rounded-full',          // hover          'hover:bg-bg-weak-50',        ],      },      group: {        root: 'divide-x divide-stroke-soft-200 overflow-hidden rounded-lg border border-stroke-soft-200',        item: [          // base          'h-8 min-w-10 px-1.5',          // hover          'hover:bg-bg-weak-50',        ],        navButton: [          // base          'h-8 w-10 px-1.5',          // hover          'hover:bg-bg-weak-50',        ],      },    },  },  defaultVariants: {    variant: 'basic',  },});type PaginationSharedProps = VariantProps<typeof paginationVariants>;type PaginationRootProps = React.HTMLAttributes<HTMLDivElement> &  VariantProps<typeof paginationVariants> & {    asChild?: boolean;  };function PaginationRoot({  asChild,  children,  className,  variant,  ...rest}: PaginationRootProps) {  const uniqueId = React.useId();  const Component = asChild ? Slot : 'div';  const { root } = paginationVariants({ variant });  const sharedProps: PaginationSharedProps = {    variant,  };  const extendedChildren = recursiveCloneChildren(    children as React.ReactElement[],    sharedProps,    [      PAGINATION_ITEM_NAME,      PAGINATION_NAV_BUTTON_NAME,      PAGINATION_NAV_ICON_NAME,    ],    uniqueId,    asChild,  );  return (    <Component className={root({ class: className })} {...rest}>      {extendedChildren}    </Component>  );}PaginationRoot.displayName = PAGINATION_ROOT_NAME;type PaginationItemProps = React.ButtonHTMLAttributes<HTMLButtonElement> &  PaginationSharedProps & {    asChild?: boolean;    current?: boolean;  };const PaginationItem = React.forwardRef<HTMLButtonElement, PaginationItemProps>(  (    { asChild, children, className, variant, current, ...rest },    forwardedRef,  ) => {    const Component = asChild ? Slot : 'button';    const { item } = paginationVariants({ variant });    return (      <Component        ref={forwardedRef}        className={cn(item({ class: className }), {          'text-text-strong-950': current,        })}        {...rest}      >        {children}      </Component>    );  },);PaginationItem.displayName = PAGINATION_ITEM_NAME;type PaginationNavButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &  PaginationSharedProps & {    asChild?: boolean;  };const PaginationNavButton = React.forwardRef<  HTMLButtonElement,  PaginationNavButtonProps>(({ asChild, children, className, variant, ...rest }, forwardedRef) => {  const Component = asChild ? Slot : 'button';  const { navButton } = paginationVariants({ variant });  return (    <Component      ref={forwardedRef}      className={navButton({ class: className })}      {...rest}    >      {children}    </Component>  );});PaginationNavButton.displayName = PAGINATION_NAV_BUTTON_NAME;function PaginationNavIcon<T extends React.ElementType>({  variant,  className,  as,  ...rest}: PolymorphicComponentProps<T, PaginationSharedProps>) {  const Component = as || 'div';  const { navIcon } = paginationVariants({ variant });  return <Component className={navIcon({ class: className })} {...rest} />;}PaginationNavIcon.displayName = PAGINATION_NAV_ICON_NAME;export {  PaginationRoot as Root,  PaginationItem as Item,  PaginationNavButton as NavButton,  PaginationNavIcon as NavIcon,};

Examples

variant="rounded"

variant="group"

API Reference

Pagination.Root

The root component for pagination. Wraps around pagination items and navigation buttons. This component is based on the <div> element and supports all of its props. And adds:

PropTypeDefault
variant"basic" | "rounded" | "group""basic"
asChildboolean

Pagination.Item

An individual pagination item, typically a link. This component is based on the <button> element and supports all of its props. And adds:

PropTypeDefault
currentboolean
asChildboolean

Pagination.NavButton

A navigation button for pagination, such as "previous" or "next". This component is based on the <button> element and supports all of its props. And adds:

PropTypeDefault
asChildboolean

Pagination.NavIcon

An icon used inside navigation buttons for pagination. This component is polymorphic, allowing you to change the underlying HTML element using the as prop.

PropTypeDefault
asReact.ElementTypediv

On this page