usePagination
A small reactive container for pagination state. Returns refs for the current page, page size, total item count and a list of available page-size options, plus imperative setters.
The defaults are conservative — page 1, 25 items per page and [5, 10, 25, 50, 100] as options. useDataTable builds on top of this composable.
Demo
243 items
Page 1 / 10
<script setup lang="ts">
import { computed } from 'vue';
import { usePagination } from '@basmilius/common';
const {limits, page, perPage, total, setPage, setPerPage, setTotal} = usePagination();
setTotal(243);
const pageCount = computed(() => Math.max(1, Math.ceil(total.value / perPage.value)));
function onPerPage(evt: Event): void {
setPerPage(Number((evt.target as HTMLSelectElement).value));
setPage(1);
}
</script>
<template>
<div class="demo">
<div class="row">
<label class="field">
Per page
<select :value="perPage" @change="onPerPage">
<option v-for="limit in limits" :key="limit" :value="limit">{{ limit }}</option>
</select>
</label>
<span class="total">{{ total }} items</span>
</div>
<div class="pager">
<button :disabled="page <= 1" @click="setPage(page - 1)">Prev</button>
<span class="label">Page {{ page }} / {{ pageCount }}</span>
<button :disabled="page >= pageCount" @click="setPage(page + 1)">Next</button>
</div>
</div>
</template>
<style scoped>
.demo {
padding: 24px;
border: 1px solid var(--vp-c-border);
border-radius: 12px;
background: var(--vp-c-bg-soft);
}
.row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.field {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: var(--vp-c-text-2);
}
.field select {
padding: 6px 10px;
border: 1px solid var(--vp-c-border);
border-radius: 8px;
background: var(--vp-c-bg);
color: var(--vp-c-text-1);
}
.total {
font-family: var(--vp-font-family-mono);
font-size: 13px;
color: var(--vp-c-text-3);
}
.pager {
display: flex;
align-items: center;
gap: 14px;
}
.pager button {
padding: 6px 14px;
border: 1px solid var(--vp-c-border);
border-radius: 8px;
background: var(--vp-c-bg);
color: var(--vp-c-text-1);
}
.pager button:disabled {
opacity: .5;
}
.label {
font-family: var(--vp-font-family-mono);
font-size: 14px;
color: var(--vp-c-text-1);
}
</style>Importing
ts
import { usePagination } from '@basmilius/common';Usage
vue
<script setup lang="ts">
import { usePagination } from '@basmilius/common';
const {
limits,
page,
perPage,
total,
setPage,
setPerPage,
setTotal
} = usePagination();
</script>
<template>
<select :value="perPage" @change="setPerPage(Number(($event.target as HTMLSelectElement).value))">
<option v-for="limit in limits" :key="limit" :value="limit">
{{ limit }}
</option>
</select>
<button :disabled="page === 1" @click="setPage(page - 1)">Previous</button>
<button :disabled="page * perPage >= total" @click="setPage(page + 1)">Next</button>
</template>Returned bindings
| Property | Type | Description |
|---|---|---|
limits | Ref<number[]> | Available page-size options |
page | Ref<number> | One-based current page (default 1) |
perPage | Ref<number> | Active page size (default 25) |
total | Ref<number> | Total number of items |
setPage(num) | (num: number) => void | Set the current page |
setPerPage(num) | (num: number) => void | Set the page size |
setTotal(num) | (num: number) => void | Set the total count |
Type signature
ts
declare function usePagination(): {
readonly limits: Ref<number[]>;
readonly page: Ref<number>;
readonly perPage: Ref<number>;
readonly total: Ref<number>;
setPage(num: number): void;
setPerPage(num: number): void;
setTotal(num: number): void;
};