Skip to main content
Vuetify0 v1.0 is here
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

BuPagination

Edit this page
Report a Bug
Open issues
Copy Markdown

Renders elementIntermediateAug 24, 2026

Bulma’s .pagination with the JavaScript it never shipped: current page, ellipses, and disabled previous and next.

Note

Reference: Pagination on bulma.io↗︎ — classes and visual variants. This page is the JavaScript.

Usage

v-model is the current page, 1-indexed. pages is how many there are. Compose BuPaginationPrev, BuPaginationNext, then BuPaginationList with BuPaginationItem / BuPaginationEllipsis children — that DOM order is load-bearing. Bulma CSS flex-orders the list between the two anchors visually; the harness diffs the source order.

<script setup lang="ts">
  import {
    BuPagination,
    BuPaginationEllipsis,
    BuPaginationItem,
    BuPaginationList,
    BuPaginationNext,
    BuPaginationPrev,
  } from '@paper/bulma'

  import { shallowRef } from 'vue'

  const page = shallowRef(2)
</script>

<template>
  <p class="is-size-7 has-text-grey mb-3">Page {{ page }} of 5</p>

  <BuPagination v-slot="{ items }" v-model="page" :pages="5">
    <BuPaginationPrev>Previous</BuPaginationPrev>

    <BuPaginationNext>Next page</BuPaginationNext>

    <BuPaginationList>
      <template v-for="(item, index) in items" :key="index">
        <BuPaginationItem v-if="item.type === 'page'" :value="item.value" />

        <BuPaginationEllipsis v-else />
      </template>
    </BuPaginationList>
  </BuPagination>
</template>

Anatomy

vue
<script setup lang="ts">
  import {
    BuPagination,
    BuPaginationEllipsis,
    BuPaginationItem,
    BuPaginationList,
    BuPaginationNext,
    BuPaginationPrev,
  } from '@paper/bulma'
</script>

<template>
  <BuPagination>
    <BuPaginationPrev />

    <BuPaginationNext />

    <BuPaginationList>
      <BuPaginationItem />

      <BuPaginationEllipsis />
    </BuPaginationList>
  </BuPagination>
</template>

Composed on v0

BuPagination maps onto v0’s Pagination compound: Pagination.Root, Pagination.Prev, Pagination.Next, Pagination.Item and Pagination.Ellipsis.

v0’s size is total items, not page count. The mapping is :size="pages" with :items-per-page="1", which is why the prop is named pages and why size / itemsPerPage never appear on this surface.

visible is totalVisible. Omit it and the root measures the container and shows as many page links as fit; pass it and the window is a hard cap, with ellipses filling the gaps.

What the parts own is the Bulma shape the compound does not: anchors (as="a") instead of buttons, is-disabled / is-current classes instead of a disabled attribute, and the consumer-authored DOM order Previous, Next, then ul.pagination-list.

The markup you know

The Bulma tab is the markup published on bulma.io↗︎, captured verbatim in the conformance fixture. The Vue tab is the component that renders it. The conformance suite diffs the two on every test run — localized aria-label text and the absence of placeholder hrefs are the tolerated differences.

html
<nav class="pagination" role="navigation" aria-label="pagination">
  <a href="#" class="pagination-previous">Previous</a>
  <a href="#" class="pagination-next">Next page</a>
  <ul class="pagination-list">
    <li>
      <a href="#" class="pagination-link" aria-label="Goto page 1">1</a>
    </li>
    <li>
      <span class="pagination-ellipsis">&hellip;</span>
    </li>
    <li>
      <a href="#" class="pagination-link" aria-label="Goto page 45">45</a>
    </li>
    <li>
      <a class="pagination-link is-current" aria-label="Page 46" aria-current="page">46</a>
    </li>
    <li>
      <a href="#" class="pagination-link" aria-label="Goto page 47">47</a>
    </li>
    <li>
      <span class="pagination-ellipsis">&hellip;</span>
    </li>
    <li>
      <a href="#" class="pagination-link" aria-label="Goto page 86">86</a>
    </li>
  </ul>
</nav>

You write no is-current and no is-disabled — Prev/Next/Item apply those from the pagination context. An out-of-range model is clamped back so the parent matches what renders. A disabled previous’s title (fixture: "This is the first page") is authored content — bind it as an attribute on BuPaginationPrev.

Examples

Visible window

visible caps how many page links are shown at once. The rest collapse behind ellipses, with the first page, the last page, and a window around the current page kept. The example is the fixture’s 86-page run with the cap at 5 — enough to force both ellipses without hiding the current page.

Omit visible and the cap is measured from the container instead. That is the right default for a pagination that should fill its bar; pass visible when the surrounding layout cannot tolerate a changing control width, or when you want the same window at every breakpoint.

The trade is information. A hard cap of 5 on 86 pages tells the reader almost nothing about where they are in the run except through the current-page mark and the first/last links. Pair it with copy that names the page, or raise the cap until the window is a useful map.

Props

BuPagination also binds v-model — the current page as a number, 1-indexed, defaulting to 1.

PropTypeDefaultDescription
pagesnumber1Total page count
visiblenumberVisible page-link cap; omit for auto-measure
ellipsisstring'…'Character between page ranges
size'small' | 'normal' | 'medium' | 'large'is-{size}
roundedbooleanis-rounded
centeredbooleanis-centered
rightbooleanis-right

The default slot receives v0’s pagination surface (items, isFirst, isLast, page, …). Iterate items to render Item/Ellipsis children.

Parts

PartPropsNotes
BuPaginationPrevnamespace.pagination-previous. Slot is the label (default Previous). Applies is-disabled on the first page
BuPaginationNextnamespace.pagination-next. Slot is the label (default Next page). Applies is-disabled on the last page
BuPaginationListul.pagination-list
BuPaginationItemvalue (number, required), namespaceli > a.pagination-link. Applies is-current when selected
BuPaginationEllipsisnamespaceli > span.pagination-ellipsis

DOM order is previous, next, then the list — CSS puts the list in the middle visually. Do not reorder in JS.

Accessibility

The root is a nav whose accessible name comes from the locale key Pagination.label. Page links, previous and next are anchors, not buttons: disabled is omitted (it is not valid on <a>), and the inert state is is-disabled plus aria-disabled and tabindex="-1". The current page is is-current with aria-current="page".

Enter and Space activate those anchors. Ellipses are aria-hidden. Page-link names come from the locale keys Pagination.goToPage and Pagination.currentPage — do not copy the fixture’s “Goto page N” strings; they are documentation placeholders, and the conformance suite ignores the difference on purpose.

Was this page helpful?

© 2016-1970 Vuetify, LLC
Services
Ctrl+/