Appearance
@vibe-labs/design-vue-pagination
Vue 3 pagination component for the Vibe Design System. Windowed page range with ellipsis, keyboard accessible, and a standalone composable for headless usage.
Installation
ts
import { VibePagination } from "@vibe-labs/design-vue-pagination";Requires the CSS layer from @vibe-labs/design-components-pagination.
Components
VibePagination
Page navigation with automatic windowing and ellipsis.
Usage
vue
<!-- Basic -->
<VibePagination v-model:page="currentPage" :total-pages="20" />
<!-- Custom visible range -->
<VibePagination v-model:page="currentPage" :total-pages="50" :siblings="9" />
<!-- Without prev/next buttons -->
<VibePagination v-model:page="currentPage" :total-pages="10" :show-prev-next="false" />
<!-- Custom prev/next labels -->
<VibePagination v-model:page="currentPage" :total-pages="10" prev-label="‹" next-label="›" />
<!-- Custom prev/next slots -->
<VibePagination v-model:page="currentPage" :total-pages="10">
<template #prev><ChevronLeftIcon /></template>
<template #next><ChevronRightIcon /></template>
</VibePagination>
<!-- Custom page slot -->
<VibePagination v-model:page="currentPage" :total-pages="10">
<template #page="{ page, active }">
<span :class="{ 'font-bold': active }">{{ page }}</span>
</template>
</VibePagination>
<!-- Disabled -->
<VibePagination v-model:page="currentPage" :total-pages="10" disabled />Windowing Examples
page=1, totalPages=20, siblings=7 → [1, 2, 3, 4, 5, 6, 7, …, 20]
page=5, totalPages=20, siblings=7 → [1, …, 4, 5, 6, 7, 8, …, 20]
page=20, totalPages=20, siblings=7 → [1, …, 14, 15, 16, 17, 18, 19, 20]
page=3, totalPages=5, siblings=7 → [1, 2, 3, 4, 5]Props
| Prop | Type | Default | Description |
|---|---|---|---|
page | number | required | Current page, 1-based (v-model:page) |
totalPages | number | required | Total number of pages |
siblings | number | 7 | Max visible page buttons (odd numbers work best) |
showPrevNext | boolean | true | Show previous/next buttons |
prevLabel | string | "←" | Previous button text |
nextLabel | string | "→" | Next button text |
disabled | boolean | false | Disable all interaction |
ariaLabel | string | "Pagination" | Nav element label |
Events
| Event | Payload | Description |
|---|---|---|
update:page | number | Page changed |
Slots
| Slot | Props | Description |
|---|---|---|
prev | — | Custom previous button content |
next | — | Custom next button content |
page | { page: number, active: boolean } | Custom page button content |
ellipsis | — | Custom ellipsis content |
Accessibility
- Wrapped in
<nav>with configurablearia-label - Active page marked with
aria-current="page" - Prev/next buttons have
aria-labelandaria-disabled - Each page button has
aria-label="Page N"
Composable
usePagination(options)
Headless pagination logic — use when you need the windowing algorithm without the component.
ts
import { usePagination } from "@vibe-labs/design-vue-pagination";
const { items, hasPrev, hasNext, hasPages } = usePagination({
page: toRef(props, "page"),
totalPages: toRef(props, "totalPages"),
siblings: 7,
});Returns
| Property | Type | Description |
|---|---|---|
items | ComputedRef<PageItem[]> | Page items to render |
hasPrev | ComputedRef<boolean> | Can go to previous page |
hasNext | ComputedRef<boolean> | Can go to next page |
hasPages | ComputedRef<boolean> | Has any pages at all |
PageItem Type
ts
type PageItem = { type: "page"; page: number } | { type: "ellipsis"; key: string };Dependencies
| Package | Purpose |
|---|---|
@vibe-labs/design-components-pagination | CSS tokens + generated styles |
Build
bash
npm run buildBuilt with Vite + vite-plugin-dts. Outputs ES module with TypeScript declarations.