@todovue/tv-pagination
v1.1.3
Published
A simple and customizable pagination component for Vue.js applications.
Maintainers
Readme
TODOvue Pagination (TvPagination)
A pagination component for Vue 3, flexible and customizable, with support for smart ranges (sibling pages and boundaries), ellipsis, optional navigation buttons, icons, custom styles, and a slot for labels. Designed for SPAs and SSR environments (e.g. Nuxt 3) without assuming DOM details.
Demo: https://ui.todovue.blog/pagination
Table of Contents
- Features
- Installation
- Quick Start (SPA)
- Usage in Nuxt 4 / SSR
- Component Registration Options
- Props
- Events
- Slots
- Customization (Styles / Theming)
- Accessibility
- SSR Notes
- Development
- Contribute
- License
- Attributions
Features
- Automatic calculation of total pages from
totalItemsandpageSize. - Dynamic range with sibling pages (
siblingCount) and boundaries (boundaryCount). - Conditional left / right ellipsis when large jumps exist.
- Optional buttons: first / last (
showFirstLast) and previous / next (showPrevNext). - Navigation icons (internally uses
@todovue/tv-button). - Custom styles for active / inactive pages (
activeStyle,inactiveStyle). - Slot to customize each page label (
page-label). - Controlled via
v-model(current page) + semantic change event. - Ready for SSR (no direct access to
window/document). - No heavy dependencies (only
vueas peer +@todovue/tv-button). - Easy integration in TODOvue design systems.
Installation
Using npm:
npm install @todovue/tv-paginationUsing yarn:
yarn add @todovue/tv-paginationUsing pnpm:
pnpm add @todovue/tv-paginationRequires
vue@^3.@todovue/tv-buttoninstalls as a dependency.
Quick Start (SPA)
Global registration (main.js / main.ts):
import { createApp } from 'vue'
import App from './App.vue'
import { TvPagination } from '@todovue/tv-pagination'
import '@todovue/tv-pagination/style.css' // import styles
import '@todovue/tv-button/style.css' // import styles
createApp(App)
.use(TvPagination) // enables <TvPagination /> globally
.mount('#app')Local usage inside a component:
<script setup>
import { ref } from 'vue'
import { TvPagination } from '@todovue/tv-pagination'
import '@todovue/tv-pagination/style.css' // import styles
import '@todovue/tv-button/style.css' // import styles
const page = ref(1)
</script>
<template>
<TvPagination v-model="page" :total-items="500" :sibling-count="2" :boundary-count="2" />
</template>Usage in Nuxt 4 / SSR
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@todovue/tv-card/nuxt'
]
})Use anywhere:
<TvPagination v-model="page" :total-items="120" />Component Registration Options
| Approach | When to use |
|-----------------------------------------------|-------------------------------------|
| Global app.use(TvPagination) | Frequent use in many views |
| Local import { TvPagination } | Isolated contexts / code-splitting |
| Default import import TvPagination from ... | Single usage or manual registration |
| Nuxt plugin | SSR / design consistency |
Props
| Prop | Type | Default | Required | Description |
|---------------|---------|------------------------------------------------------------|----------|----------------------------------------------------------------|
| modelValue | Number | 1 | No | Current page (v-model). Normalized to valid range. |
| totalItems | Number | — | Yes | Total items being paginated. |
| pageSize | Number | 10 | No | Page size to calculate totalPages. |
| siblingCount | Number | 1 | No | Number of visible pages next to the active one. |
| boundaryCount | Number | 1 | No | Number of always-visible starting and ending pages. |
| showFirstLast | Boolean | true | No | Shows first/last page buttons. |
| showPrevNext | Boolean | true | No | Shows previous/next buttons. |
| showIcons | Boolean | false | No | Uses icons on navigation buttons (arrows). |
| disabled | Boolean | false | No | Disables all interaction. |
| ariaLabel | String | 'Pagination' | No | Accessible label for <nav>. |
| labels | Object | { first:'First', prev:'Prev', next:'Next', last:'Last' } | No | Text for navigation buttons. |
| buttonProps | Object | {} | No | Additional props (and styles) passed to each TvButton. |
| activeStyle | Object | {} | No | Inline styles for active pages ({ backgroundColor, color }). |
| inactiveStyle | Object | { backgroundColor:'#ffffff', color:'#000000' } | No | Inline styles for inactive pages. |
| square | Boolean | false | No | Controls if buttons are square. |
| size | String | 'small' | No | Button size ('small', 'md', 'large'). |
| showSummary | Boolean | false | No | Displays text showing the current range of items. |
| textSummary | String | 'Showing {from} to {to} of {total} items' | No | Template for summary text (uses {from}, {to}, {total}). |
Note: If
activeStyleis empty, TvButton default styling is used.inactiveStylealways provides white/black fallback if omitted.
Events
| Name (kebab) | Payload | Description |
|---------------------|----------|---------------------------------------------------------------------|
| update:modelValue | number | Emits new page number for v-model. |
| change | number | Semantic event triggered when the page changes (only if different). |
Example:
<TvPagination v-model="page" :total-items="300" @change="onPage" />function onPage(newPage) {
console.log('Current page:', newPage)
}Slots
| Slot | Exposed props | Description |
|--------------|--------------------|----------------------------------------|
| page-label | { page, active } | Customize content of each page button. |
Example:
<TvPagination
v-model="page"
:total-items="100"
>
<template #page-label="{ page, active }">
<span :style="active ? 'font-weight:600' : ''">Pg {{ page }}</span>
</template>
</TvPagination>Customization (Styles / Theming)
Active styles with activeStyle:
<TvPagination
v-model="page"
:total-items="300"
:active-style="{ backgroundColor: '#10b981', color: '#ffffff' }"
/>Inactive styles:
<TvPagination
v-model="page"
:total-items="300"
:inactive-style="{ backgroundColor: '#f1f5f9', color: '#0f172a' }"
/>Passing styles / variants to base button via buttonProps:
<TvPagination
v-model="page"
:total-items="120"
:button-props="{ outlined: true, small: true }"
/>All
buttonPropsvalues are passed to eachTvButtoninstance (including variants likesuccess,outlined,small, etc.).
Accessibility
navcontainer with configurablearia-label(ariaLabel).- Active page receives
aria-current="page". - Ellipsis marked with
aria-hidden="true"and are not focusable. - Disabled buttons use
disabledattribute (inherited fromTvButton). - If icons are used (
showIcons=true) accessible text is preserved (or empty for icon-only). Ensurelabels.*describe the action.
SSR Notes
- No direct DOM access → safe for server rendering.
- Styles are served as a separate CSS file (
dist/tv-pagination.css) that must be explicitly imported (see Importing Styles). vueis marked as external in the library build (tree-shake friendly).- Compatible with Nuxt 3/4 by adding the stylesheet to the
cssarray innuxt.config.ts.
Development
git clone https://github.com/TODOvue/tv-pagination.git
cd tv-pagination
npm install
npm run dev # runs playground demo (Vite)
npm run build # builds the libraryBuild demo (uses environment variable):
npm run build:demo # generates dist-demo with README in public/Output structure:
dist/tv-pagination.es.jsdist/tv-pagination.cjs.js- Types:
dist/tv-pagination.d.ts
Contribute
PRs and issues are welcome! See CONTRIBUTING.md and CODE_OF_CONDUCT.md.
License
MIT © TODOvue
Attributions
Created for the TODOvue component ecosystem.
