Vue Pagination

December 17, 2025 ยท View on GitHub

Vue Pagination is a simple and flexible Vue 3 pagination component written in TypeScript. It focuses only on pagination UI and events, not data fetching or state management.

You control the logic. The component only handles rendering and user interaction.


Why this component

Many pagination components try to do too much.

This one:

  • does one job
  • stays predictable
  • stays small
  • stays reusable

If you already manage pagination logic in your app, this component fits well.


Features

  • Vue 3 (Composition API)
  • Fully typed with TypeScript
  • Small bundle size
  • Slot-based customization
  • No CSS or UI framework
  • Works with REST or GraphQL APIs
  • ESM and CommonJS support

Installation

npm install vue-pagination

Peer dependency:

  • Vue version 3.3 or higher

Basic usage

Import the component

import Pagination from "vue-pagination"

Pagination state example

import { ref } from "vue"

const pagination = ref({
  page: 0,
  rowsPerPage: 10,
  total: 100,
  totalPage: 10
})

Use in template

<Pagination
  :pagination="pagination"
  @page-change="onPageChange"
  @row-change="onRowChange"
/>

Handle events

const onPageChange = (page: number) => {
  pagination.value.page = page
  // fetch data here
}

const onRowChange = (rows: number) => {
  pagination.value.rowsPerPage = rows
  pagination.value.page = 0
  // refetch data here
}

How it works

  • The component does not fetch data

  • The component does not modify state

  • It only:

    • displays pagination UI
    • emits events when the user interacts

This keeps the component easy to test and easy to reuse.


Slots and customization

All UI parts are customizable using slots. If a slot is not provided, a default UI is rendered.


Info slot

<template #info="{ pagination }">
  <span>
    Page {{ pagination.page + 1 }} of {{ pagination.totalPage }}
  </span>
</template>

Rows per page slot

<template #rows="{ onChange }">
  <select @change="onChange">
    <option :value="5">5</option>
    <option :value="10">10</option>
    <option :value="25">25</option>
  </select>
</template>

Button slots

Available slots:

  • first
  • prev
  • next
  • last

Example:

<template #next="{ go, disabled }">
  <button :disabled="disabled" @click="go">
    Next page
  </button>
</template>

Each button slot receives:

  • go() function to trigger page change
  • disabled boolean

Events

Event namePayloadDescription
page-changenumberEmitted when page changes
row-changenumberEmitted when rows per page changes

Types

Pagination state interface:

export interface PaginationState {
  page: number
  rowsPerPage: number
  total: number
  totalPage: number
}

TypeScript users get full IntelliSense support.


Visibility behavior

The pagination UI is automatically hidden when:

totalPage <= 1

If there is only one page, pagination controls are not shown.


Styling

This package does not include CSS.

You are free to style it using:

  • plain CSS
  • CSS modules
  • Tailwind
  • any other approach

Example:

.pagination {
  display: flex;
  gap: 8px;
  align-items: center;
}

When to use this component

Good fit if:

  • you want control over pagination logic
  • you do not want a UI framework
  • you prefer simple, explicit APIs

Not a good fit if:

  • you want a ready-made design system
  • you want pagination to fetch data automatically

License

MIT license.


Final note

This component is intentionally simple. It focuses on correctness and flexibility rather than appearance.

If you find issues or want improvements, contributions are welcome.