Pagination

Pagination with page navigation, next and previous links.

Examples

Basic

PropDefaultTypeDescription
total0numberThe total number of items in your list.
defaultPage1numberThe value of the page that should be active when initially rendered. Use when you do not need to control the value state.
disabledfalsebooleanWhen true, prevents the user from interacting with item.
itemsPerPage10numberNumber of items per page.
page-numberThe controlled value of the current page. Can be binded as v-model:page.
showEdgesfalsebooleanWhen true, always show first page, last page, and ellipsis.
Preview
Code

Sibling Count

PropDefaultTypeDescription
siblingCount2numberThe number of surrounding pages displayed around the current page.
Preview
Code

Visibility

PropDefaultTypeDescription
showFirsttruebooleanDisplays the first page button.
showLasttruebooleanDisplays the last page button.
showPrevtruebooleanDisplays the previous page button.
showNexttruebooleanDisplays the next page button.
showListItemtruebooleanDisplays the list items.
Preview
Code
Current Page: 1

Size

PropDefaultTypeDescription
sizesmstringAdjusts the size of the entire pagination.
firstPageSizesmstringCustomizes the size of the first page button.
lastPageSizesmstringCustomizes the size of the last page button.
prevPageSizesmstringCustomizes the size of the previous page button.
nextPageSizesmstringCustomizes the size of the next page button.
listItemSizesmstringCustomizes the size of the page list items.
ellipsisSizesmstringCustomizes the size of the ellipsis indicator.
Preview
Code

Variant and Color

PropDefaultTypeDescription
pagination-selectedsolid-primary{variant}-{color}The color of the selected page.
pagination-unselectedsolid-white{variant}-{color}The color of the unselected page.
pagination-ellipsistext-black{variant}-{color}The color of the ellipsis.
Preview
Code

Rounded

Preview
Code

Sub Components

PropAPI referenceDescription
_pagination-list-itemRadix Pagination ListItem APICustomizes the pagination list item component.
_pagination-prevRadix Pagination Prev APICustomizes the previous page navigation button.
_pagination-nextRadix Pagination Next APICustomizes the next page navigation button.
_pagination-firstRadix Pagination First APICustomizes the first page navigation button.
_pagination-lastRadix Pagination Last APICustomizes the last page navigation button.
_pagination-ellipsisRadix Pagination Ellipsis APICustomizes the ellipsis indicator in the pagination.
_pagination-listRadix Pagination List APICustomizes the pagination list component.
Preview
Code

Slots

NamePropsDescription
first-Customizes the first page navigation button.
last-Customizes the last page navigation button.
prev-Customizes the previous page navigation button.
next-Customizes the next page navigation button.
list-itemitem, pageCustomizes the pagination list item component.
ellipsis-Customizes the ellipsis indicator in the pagination.
Preview
Code

Presets

shortcuts/pagination.ts
type PaginationPrefix = 'pagination'

export const staticPagination: Record<`${PaginationPrefix}-${string}` | PaginationPrefix, string> = {
  // configurations
  'pagination': 'overflow-hidden',
  'pagination-list': 'flex items-center gap-1 overflow-hidden',

  // components
  'pagination-root': '',
  'pagination-list-item': 'pagination',

  'pagination-ellipsis-base': 'btn flex items-center justify-center',
  'pagination-ellipsis-icon-base': 'w-1em h-1em',
  'pagination-ellipsis-icon': 'i-lucide-ellipsis',

  'pagination-first': 'pagination',
  'pagination-first-icon': 'i-lucide-chevrons-left',

  'pagination-prev': 'pagination',
  'pagination-prev-icon': 'i-lucide-chevron-left',

  'pagination-next': 'pagination',
  'pagination-next-icon': 'i-lucide-chevron-right',

  'pagination-last': 'pagination',
  'pagination-last-icon': 'i-lucide-chevrons-right',
}

export const dynamicPagination = [
  [
    /^pagination-ellipsis(?:-([^-]+))?(?:-([^-]+))?$/,
    ([, variant = 'text', color = 'black']) =>
      `btn-${variant}-${color}`,
  ],

  [
    /^pagination-selected(?:-([^-]+))?(?:-([^-]+))?$/,
    ([, variant = 'solid', color = 'primary']) =>
      `data-[selected=true]:btn-${variant}-${color}`,
  ],
  [
    /^pagination-unselected(?:-([^-]+))?(?:-([^-]+))?$/,
    ([, variant = 'solid', color = 'white']) =>
      `data-[selected=false]:btn-${variant}-${color}`,
  ],

]

export const pagination = [
  ...dynamicPagination,
  staticPagination,
]

Props

types/pagination.ts
import type { PaginationEllipsisProps, PaginationFirstProps, PaginationLastProps, PaginationListItemProps, PaginationListProps, PaginationNextProps, PaginationPrevProps, PaginationRootProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'
import type { NButtonProps } from './button'

interface BaseExtensionProps {
  square?: HTMLAttributes['class']
  class?: HTMLAttributes['class']
  rounded?: HTMLAttributes['class']
  size?: HTMLAttributes['class']
}

type isVisible = boolean

export interface NPaginationProps extends
  PaginationRootProps,
  BaseExtensionProps,
  Pick<NButtonProps, 'paginationSelected' | 'paginationUnselected'>,
  Pick<NPaginationEllipsisProps, 'paginationEllipsis'> {
  showFirst?: isVisible
  showPrev?: isVisible
  showNext?: isVisible
  showLast?: isVisible
  showListItem?: isVisible

  // sub-components
  _paginationList?: Partial<NPaginationListProps>
  _paginationListItem?: Partial<NPaginationListItemProps>
  _paginationEllipsis?: Partial<NPaginationEllipsisProps>
  _paginationFirst?: Partial<NPaginationFirstProps>
  _paginationPrev?: Partial<NPaginationPrevProps>
  _paginationNext?: Partial<NPaginationNextProps>
  _paginationLast?: Partial<NPaginationLastProps>

  una?: NPaginationUnaProps
}

export interface NPaginationListProps extends PaginationListProps, BaseExtensionProps {
  una?: Pick<NPaginationUnaProps, 'paginationList'>
}

export interface NPaginationListItemProps extends PaginationListItemProps, NButtonProps {
  isSelected?: boolean
  page?: PaginationRootProps['page']
}

export interface NPaginationEllipsisProps extends PaginationEllipsisProps, BaseExtensionProps {
  paginationEllipsis?: HTMLAttributes['class']

  una?: Pick<NPaginationUnaProps, 'paginationEllipsis' | 'paginationEllipsisIconBase' | 'paginationEllipsisIcon'>
}

export interface NPaginationFirstProps extends PaginationFirstProps, NButtonProps {
}

export interface NPaginationPrevProps extends PaginationPrevProps, NButtonProps {
}

export interface NPaginationNextProps extends PaginationNextProps, NButtonProps {
}

export interface NPaginationLastProps extends PaginationLastProps, NButtonProps {
}

interface NPaginationUnaProps {
  paginationRoot?: HTMLAttributes['class']
  paginationList?: HTMLAttributes['class']
  paginationListItem?: HTMLAttributes['class']
  paginationEllipsis?: HTMLAttributes['class']
  paginationEllipsisIconBase?: HTMLAttributes['class']
  paginationEllipsisIcon?: HTMLAttributes['class']
}

Components

Pagination.vue
PaginationEllipsis.vue
PaginationListItem.vue
PaginationFirst.vue
PaginationLast.vue
PaginationNext.vue
PaginationPrev.vue
<script setup lang="ts">
import type { NPaginationProps } from '../../../types'
import { reactivePick } from '@vueuse/core'
import { PaginationList, PaginationRoot, type PaginationRootEmits, useForwardPropsEmits } from 'radix-vue'
import { cn } from '../../../utils'
import PaginationEllipsis from './PaginationEllipsis.vue'
import PaginationFirst from './PaginationFirst.vue'
import PaginationLast from './PaginationLast.vue'
import PaginationListItem from './PaginationListItem.vue'
import PaginationNext from './PaginationNext.vue'
import PaginationPrev from './PaginationPrev.vue'

const props = withDefaults(defineProps<NPaginationProps>(), {
  showFirst: true,
  showLast: true,
  showListItem: true,
  showNext: true,
  showPrev: true,
})

const emits = defineEmits<PaginationRootEmits>()
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'defaultPage', 'disabled', 'itemsPerPage', 'page', 'showEdges', 'siblingCount', 'total'), emits)
</script>

<template>
  <PaginationRoot
    v-slot="{ page }"
    v-bind="rootProps"
    :class="cn(
      'pagination-root',
      props.class,
      props.una?.paginationRoot,
    )"
  >
    <PaginationList
      v-slot="{ items }"
      :class="cn(
        'pagination-list',
        props?._paginationList?.class,
        props.una?.paginationList,
      )"
      v-bind="_paginationList"
    >
      <slot>
        <PaginationFirst
          v-if="showFirst"
          :rounded
          :size
          :pagination-selected
          :pagination-unselected
          v-bind="_paginationFirst"
        >
          <slot
            name="first"
          />
        </PaginationFirst>

        <PaginationPrev
          v-if="showPrev"
          :rounded
          :pagination-selected
          :pagination-unselected
          :size
          v-bind="_paginationPrev"
        >
          <slot
            name="prev"
          />
        </PaginationPrev>

        <template v-if="showListItem">
          <template v-for="(item, index) in items">
            <slot
              v-if="item.type === 'page'"
              name="list-item"
              :item="item"
              :page="page"
            >
              <PaginationListItem
                :key="index"
                :value="item.value"
                :page
                :rounded
                :size
                :pagination-selected
                :pagination-unselected
                v-bind="_paginationListItem"
              />
            </slot>

            <PaginationEllipsis
              v-else
              :key="item.type"
              :index="index"
              :rounded
              :size
              :pagination-ellipsis
              :una
              v-bind="_paginationEllipsis"
            >
              <slot
                name="ellipsis"
              />
            </PaginationEllipsis>
          </template>
        </template>

        <PaginationNext
          v-if="showNext"
          :rounded
          :size
          :pagination-selected
          :pagination-unselected
          v-bind="_paginationNext"
        >
          <slot
            name="next"
          />
        </PaginationNext>

        <PaginationLast
          v-if="showLast"
          :rounded
          :size
          :pagination-selected
          :pagination-unselected
          v-bind="_paginationLast"
        >
          <slot
            name="last"
          />
        </PaginationLast>
      </slot>
    </PaginationList>
  </PaginationRoot>
</template>