Pagination

Pagination component with page numbers, supporting custom sibling count, responsive collapsing, different sizes, and global theme configuration.

Built on top of Radix Vue Pagination and BrConfigProvider.

Component Features

  • 📄 Complete Navigation: Displays page numbers, previous/next, first/last page controls.
  • 👥 Custom Sibling Count: Configures the number of visible page siblings on each side.
  • 📱 Edge Pages: Supports displaying first and last page buttons.
  • 📐 Responsive Collapsing: Automatically collapses page numbers on small screens.
  • 📏 Multiple Sizes: Supports sm, md, lg size specs.
  • 🎨 Theme Customization: Based on BrConfigProvider for global theming and TailwindCSS local overrides.

Basic Usage

The most basic pagination, binding the current page number via v-model:page.

<script setup lang="ts">
import { ref } from 'vue'
import {
  BrPagination,
  BrPaginationContent,
  BrPaginationEllipsis,
  BrPaginationFirst,
  BrPaginationItem,
  BrPaginationLast,
  BrPaginationLink,
  BrPaginationNext,
  BrPaginationPrevious,
} from '@breezeui/vue'

const currentPage = ref(1)
</script>

<template>
  <div class="flex flex-col items-center gap-4">
    <BrPagination v-model:page="currentPage" :total="100" :sibling-count="1" show-edges>
      <BrPaginationContent v-slot="{ items }">
        <BrPaginationFirst />
        <BrPaginationPrevious />

        <template v-for="(page, index) in items" :key="index">
          <BrPaginationItem v-if="page.type === 'page'">
            <BrPaginationLink :value="page.value" :is-active="page.value === currentPage">
              {{ page.value }}
            </BrPaginationLink>
          </BrPaginationItem>
          <BrPaginationEllipsis v-else :key="page.type" :index="index" />
        </template>

        <BrPaginationNext />
        <BrPaginationLast />
      </BrPaginationContent>
    </BrPagination>
    <div class="text-sm text-muted-foreground">Current page: {{ currentPage }}</div>
  </div>
</template>

Custom Sibling Count

Control the number of page numbers shown on each side of the current page via the sibling-count prop.

<script setup lang="ts">
import { ref } from 'vue'
import {
  BrPagination,
  BrPaginationContent,
  BrPaginationEllipsis,
  BrPaginationFirst,
  BrPaginationItem,
  BrPaginationLast,
  BrPaginationLink,
  BrPaginationNext,
  BrPaginationPrevious,
} from '@breezeui/vue'

const currentPage = ref(1)
</script>

<template>
  <div class="flex flex-col items-center gap-4">
    <BrPagination v-model:page="currentPage" :total="100" :sibling-count="3" show-edges>
      <BrPaginationContent v-slot="{ items }">
        <BrPaginationFirst />
        <BrPaginationPrevious />

        <template v-for="(page, index) in items" :key="index">
          <BrPaginationItem v-if="page.type === 'page'">
            <BrPaginationLink :value="page.value" :is-active="page.value === currentPage">
              {{ page.value }}
            </BrPaginationLink>
          </BrPaginationItem>
          <BrPaginationEllipsis v-else :key="page.type" :index="index" />
        </template>

        <BrPaginationNext />
        <BrPaginationLast />
      </BrPaginationContent>
    </BrPagination>
    <div class="text-sm text-muted-foreground">Sibling count: 3</div>
  </div>
</template>

Different Sizes

Supports xs, sm, md, lg, xl, 2xl size variants.

<script setup lang="ts">
import { ref } from 'vue'
import {
  BrPagination,
  BrPaginationContent,
  BrPaginationEllipsis,
  BrPaginationItem,
  BrPaginationLink,
  BrPaginationNext,
  BrPaginationPrevious,
} from '@breezeui/vue'
import type { PaginationSize } from '@breezeui/vue'

const currentPage = ref(1)
const sizes: { label: string; value: PaginationSize }[] = [
  { label: 'Extra Small (xs)', value: 'xs' },
  { label: 'Small (sm)', value: 'sm' },
  { label: 'Medium (md)', value: 'md' },
  { label: 'Large (lg)', value: 'lg' },
  { label: 'Extra Large (xl)', value: 'xl' },
  { label: '2 Extra Large (2xl)', value: '2xl' },
]
</script>

<template>
  <div class="flex flex-col items-center gap-8">
    <div v-for="size in sizes" :key="size.value" class="flex flex-col items-center gap-2">
      <span class="text-sm font-medium text-muted-foreground">{{ size.label }}</span>
      <BrPagination v-model:page="currentPage" :total="50" :size="size.value">
        <BrPaginationContent v-slot="{ items }">
          <BrPaginationPrevious />
          <template v-for="(page, index) in items" :key="index">
            <BrPaginationItem v-if="page.type === 'page'">
              <BrPaginationLink :value="page.value" :is-active="page.value === currentPage">
                {{ page.value }}
              </BrPaginationLink>
            </BrPaginationItem>
            <BrPaginationEllipsis v-else :key="page.type" :index="index" />
          </template>
          <BrPaginationNext />
        </BrPaginationContent>
      </BrPagination>
    </div>
  </div>
</template>

Responsive Pagination

Combine with useWindowSize from @vueuse/core to dynamically control sibling-count for automatic collapsing on smaller screens.

<script setup lang="ts">
import { ref, computed } from 'vue'
import { useWindowSize } from '@vueuse/core'
import {
  BrPagination,
  BrPaginationContent,
  BrPaginationEllipsis,
  BrPaginationFirst,
  BrPaginationItem,
  BrPaginationLast,
  BrPaginationLink,
  BrPaginationNext,
  BrPaginationPrevious,
} from '@breezeui/vue'

const currentPage = ref(1)
const { width } = useWindowSize()
const responsiveSiblingCount = computed(() => (width.value < 640 ? 0 : 2))
</script>

<template>
  <div class="flex flex-col items-center gap-4">
    <BrPagination v-model:page="currentPage" :total="100" :sibling-count="responsiveSiblingCount" show-edges>
      <BrPaginationContent v-slot="{ items }">
        <BrPaginationFirst />
        <BrPaginationPrevious />

        <template v-for="(page, index) in items" :key="index">
          <BrPaginationItem v-if="page.type === 'page'">
            <BrPaginationLink :value="page.value" :is-active="page.value === currentPage">
              {{ page.value }}
            </BrPaginationLink>
          </BrPaginationItem>
          <BrPaginationEllipsis v-else :key="page.type" :index="index" />
        </template>

        <BrPaginationNext />
        <BrPaginationLast />
      </BrPaginationContent>
    </BrPagination>
    <div class="text-sm text-muted-foreground">
      Try resizing the window width (&lt; 640px)
    </div>
  </div>
</template>

Theming

The colors (primary, active color), border radius, and sizes of the BrPagination component are fully implemented based on CSS variables provided by BrConfigProvider.

<script setup lang="ts">
import { ref } from 'vue'
import {
  BrConfigProvider,
  BrPagination,
  BrPaginationContent,
  BrPaginationEllipsis,
  BrPaginationFirst,
  BrPaginationItem,
  BrPaginationLast,
  BrPaginationLink,
  BrPaginationNext,
  BrPaginationPrevious,
} from '@breezeui/vue'

const currentPage = ref(1)
const customTheme = {
  primary: '#10b981', // Custom active color (Emerald-500)
  radius: 1.5, // Larger border radius
}
</script>

<template>
  <BrConfigProvider :theme="customTheme">
    <div class="flex justify-center p-4 border rounded-lg bg-background">
      <BrPagination v-model:page="currentPage" :total="100" :sibling-count="1" show-edges>
        <BrPaginationContent v-slot="{ items }">
          <BrPaginationFirst />
          <BrPaginationPrevious />

          <template v-for="(page, index) in items" :key="index">
            <BrPaginationItem v-if="page.type === 'page'">
              <BrPaginationLink :value="page.value" :is-active="page.value === currentPage">
                {{ page.value }}
              </BrPaginationLink>
            </BrPaginationItem>
            <BrPaginationEllipsis v-else :key="page.type" :index="index" />
          </template>

          <BrPaginationNext />
          <BrPaginationLast />
        </BrPaginationContent>
      </BrPagination>
    </div>
  </BrConfigProvider>
</template>

You can also locally override via TailwindCSS:

<BrPaginationLink class="rounded-full border-blue-500 text-blue-500" />

API

BrPagination

PropTypeDefaultDescription
totalnumber-Total number of items
page (v-model)number1Current page number
itemsPerPagenumber10Number of items per page
siblingCountnumber1Number of page numbers shown on each side of the current page
showEdgesbooleanfalseWhether to always show the first and last page numbers
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl''md'Pagination button size, overrides global configuration
PropTypeDefaultDescription
valuenumber-The value of the corresponding page number
isActivebooleanfalseWhether it is active
disabledbooleanfalseWhether it is disabled
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'-Size variant

Other Sub-components

BrPaginationPrevious, BrPaginationNext, BrPaginationFirst, BrPaginationLast, etc. all support passing class to override styles via TailwindCSS.