Skip to main content
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

Pagination

A headless component for creating page navigation with proper ARIA support.

Edit
Report a Bug
Issues
Source
Markdown

PreviewRenders elementIntermediateOct 20, 2026

Usage

The Pagination component provides a compound component pattern for building page navigation interfaces. It adjusts how many page buttons it shows to fit the available width, collapsing the overflow behind ellipses.

The two core props are size (total item count) and items-per-page (items per page, default 10). Together they determine the page count:

vue
<template>
  <!-- 200 items at 10 per page = 20 pages -->
  <Pagination.Root :size="200" :items-per-page="10" v-model="page" />

  <!-- 200 items at 25 per page = 8 pages -->
  <Pagination.Root :size="200" :items-per-page="25" v-model="page" />
</template>
Theme
Mode
Palettes
Accessibility
basic.vue
<script setup lang="ts">
  import { Pagination } from '@vuetify/v0'
  import { shallowRef } from 'vue'

  const model = shallowRef(4)
</script>

<template>
  <Pagination.Root
    v-slot="{ items }"
    v-model="model"
    class="flex items-center justify-center gap-1"
    :size="200"
  >
    <Pagination.First class="w-9 h-9 rounded border border-divider flex items-center justify-center bg-surface hover:bg-surface-tint data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed">
      «
    </Pagination.First>

    <Pagination.Prev class="w-9 h-9 rounded border border-divider flex items-center justify-center bg-surface hover:bg-surface-tint data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed">
      ‹
    </Pagination.Prev>

    <template v-for="(item, index) in items" :key="index">
      <Pagination.Ellipsis
        v-if="item.type === 'ellipsis'"
        class="w-9 h-9 flex items-center justify-center text-on-surface opacity-60"
      />

      <Pagination.Item
        v-else
        class="w-9 h-9 rounded border border-divider flex items-center justify-center bg-surface hover:bg-surface-tint data-[selected]:bg-primary data-[selected]:text-on-primary data-[selected]:border-primary data-[selected]:hover:bg-primary"
        :value="item.value as number"
      >
        {{ item.value }}
      </Pagination.Item>
    </template>

    <Pagination.Next class="w-9 h-9 rounded border border-divider flex items-center justify-center bg-surface hover:bg-surface-tint data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed">
      ›
    </Pagination.Next>

    <Pagination.Last class="w-9 h-9 rounded border border-divider flex items-center justify-center bg-surface hover:bg-surface-tint data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed">
      »
    </Pagination.Last>
  </Pagination.Root>
</template>

Anatomy

vue
<script setup lang="ts">
  import { Pagination } from '@vuetify/v0'
</script>

<template>
  <Pagination.Root>
    <Pagination.Status />

    <Pagination.First />

    <Pagination.Prev />

    <Pagination.Ellipsis />

    <Pagination.Item />

    <Pagination.Next />

    <Pagination.Last />
  </Pagination.Root>
</template>
Note

Page buttons can have different widths. Pagination measures the buttons on screen, drops a slot when the row overflows, and adds one when the container has room. A wide page number shrinks the row. Leaving that page, or widening the container, grows it back. total-visible caps how many slots it may show.

Accessibility

The Pagination component renders semantic HTML and manages ARIA attributes automatically:

  • Wraps controls in a <nav> element whose aria-label defaults to "Pagination" (localizable via the Pagination.label key) for landmark navigation

  • Current page button is marked with aria-current="page" so screen readers announce it as the active page

  • Enter and Space select the focused page. Arrow keys do not move between page buttons

  • Page changes are announced only if you render Pagination.Status, which carries aria-live="polite"

For custom implementations, use renderless mode and bind the attrs slot prop to preserve all ARIA attributes:

vue
<template>
  <Pagination.Root v-slot="{ attrs }" renderless>
    <nav v-bind="attrs">
      <!-- Custom pagination controls -->
    </nav>
  </Pagination.Root>
</template>

FAQ

Discord
Need help? Join our community for support and discussions ↗
Was this page helpful?

© 2016-1970 Vuetify, LLC
Services
Ctrl+/