Skip to content

@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

PropTypeDefaultDescription
pagenumberrequiredCurrent page, 1-based (v-model:page)
totalPagesnumberrequiredTotal number of pages
siblingsnumber7Max visible page buttons (odd numbers work best)
showPrevNextbooleantrueShow previous/next buttons
prevLabelstring"←"Previous button text
nextLabelstring"→"Next button text
disabledbooleanfalseDisable all interaction
ariaLabelstring"Pagination"Nav element label

Events

EventPayloadDescription
update:pagenumberPage changed

Slots

SlotPropsDescription
prevCustom previous button content
nextCustom next button content
page{ page: number, active: boolean }Custom page button content
ellipsisCustom ellipsis content

Accessibility

  • Wrapped in <nav> with configurable aria-label
  • Active page marked with aria-current="page"
  • Prev/next buttons have aria-label and aria-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

PropertyTypeDescription
itemsComputedRef<PageItem[]>Page items to render
hasPrevComputedRef<boolean>Can go to previous page
hasNextComputedRef<boolean>Can go to next page
hasPagesComputedRef<boolean>Has any pages at all

PageItem Type

ts
type PageItem = { type: "page"; page: number } | { type: "ellipsis"; key: string };

Dependencies

PackagePurpose
@vibe-labs/design-components-paginationCSS tokens + generated styles

Build

bash
npm run build

Built with Vite + vite-plugin-dts. Outputs ES module with TypeScript declarations.