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>
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 (< 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
Other Sub-components
BrPaginationPrevious, BrPaginationNext, BrPaginationFirst, BrPaginationLast, etc. all support passing class to override styles via TailwindCSS.