UIPagination
UIPagination
A versatile pagination component that provides intuitive navigation through paginated content with support for various layouts, sizes, and customization options.
<template> <UIPagination v-model="currentPage" :total="totalItems" :pageSize="itemsPerPage" :showSizeChanger="true" :showQuickJumper="true" :showTotal="total => `Total ${total} items`" @change="handlePageChange" @sizeChange="handleSizeChange" /></template>
<script setup lang="ts">const currentPage = ref(1)const totalItems = ref(100)const itemsPerPage = ref(10)
const handlePageChange = (page: number) => { // Handle page change}
const handleSizeChange = (size: number) => { // Handle page size change}</script>Props
modelValue(number): Current page numbertotal(number): Total number of itemspageSize(number): Items per pagepageSizeOptions(array): Available page size optionsshowSizeChanger(boolean): Show page size selectorshowQuickJumper(boolean): Show quick jump inputshowTotal(function): Custom total text renderersimple(boolean): Use simple modedisabled(boolean): Disable paginationloading(boolean): Loading statesize(‘sm’ | ‘md’ | ‘lg’): Component sizehideOnSinglePage(boolean): Hide when only one pageresponsive(boolean): Enable responsive modealign(‘left’ | ‘center’ | ‘right’): Alignment
Events
update:modelValue: Page number changedchange: Page changedsizeChange: Page size changedjump: Quick jump triggered
Slots
total: Custom total contentprev: Custom previous buttonnext: Custom next buttonpageSize: Custom page size selector
Usage Examples
- Basic Pagination:
<template> <UIPagination v-model="page" :total="100" :pageSize="10" /></template>
<script setup>const page = ref(1)</script>- Advanced Data Table Pagination:
<template> <div class="space-y-4"> <UITable :data="tableData" :columns="columns" :loading="loading" />
<div class="flex items-center justify-between"> <div class="text-sm text-gray-500"> Showing {{ startIndex }} to {{ endIndex }} of {{ total }} entries </div>
<UIPagination v-model="pagination.page" :total="total" :pageSize="pagination.pageSize" :showSizeChanger="true" :pageSizeOptions="[10, 20, 50, 100]" @change="fetchData" @sizeChange="handleSizeChange" > <template #total="{ total }"> <span class="mr-4 text-sm text-gray-500"> Total {{ total }} items </span> </template> </UIPagination> </div> </div></template>
<script setup>const pagination = reactive({ page: 1, pageSize: 10})
const startIndex = computed(() => { return (pagination.page - 1) * pagination.pageSize + 1})
const endIndex = computed(() => { return Math.min(pagination.page * pagination.pageSize, total.value)})
const handleSizeChange = (size: number) => { pagination.pageSize = size pagination.page = 1 fetchData()}</script>- Infinite Scroll with Load More:
<template> <div class="space-y-4"> <div class="grid gap-4"> <ItemCard v-for="item in items" :key="item.id" :item="item" /> </div>
<div v-if="hasMore" class="flex justify-center" > <UIPagination v-model="page" :total="total" :pageSize="pageSize" :simple="true" :loading="loading" > <template #next> <UIButton :loading="loading" @click="loadMore" > Load More </UIButton> </template> </UIPagination> </div> </div></template>
<script setup>const page = ref(1)const pageSize = 20const total = ref(0)const items = ref([])const loading = ref(false)
const hasMore = computed(() => { return items.value.length < total.value})
const loadMore = async () => { if (loading.value) return loading.value = true try { const newItems = await fetchItems(page.value, pageSize) items.value.push(...newItems) page.value++ } finally { loading.value = false }}</script>Best Practices
-
User Experience:
- Clear navigation
- Visual feedback
- Consistent layout
- Responsive design
-
Performance:
- Efficient updates
- Debounced input
- Optimized rendering
- Memory management
-
Accessibility:
- ARIA labels
- Keyboard navigation
- Focus management
- Screen reader support
-
Mobile:
- Touch targets
- Simple mode
- Responsive layout
- Clear indicators
Common Use Cases
- Table Footer:
<template> <div class="flex items-center justify-between py-4"> <div class="flex items-center space-x-4"> <UISelect v-model="pageSize" :options="pageSizeOptions" size="sm" class="w-20" />
<span class="text-sm text-gray-500"> items per page </span> </div>
<UIPagination v-model="page" :total="total" :pageSize="pageSize" size="sm" /> </div></template>- Search Results:
<template> <div class="space-y-6"> <div class="text-sm text-gray-500"> {{ totalResults }} results found </div>
<div class="space-y-4"> <SearchResult v-for="result in results" :key="result.id" :result="result" /> </div>
<UIPagination v-model="page" :total="totalResults" :pageSize="10" :showQuickJumper="true" align="center" @change="handleSearch" /> </div></template>- Mobile List:
<template> <div class="space-y-4"> <div class="divide-y"> <ListItem v-for="item in items" :key="item.id" :item="item" /> </div>
<UIPagination v-model="page" :total="total" :pageSize="pageSize" :simple="true" size="lg" class="flex justify-center" > <template #prev> <UIButton variant="ghost" :disabled="page === 1" > <ChevronLeftIcon class="w-5 h-5" /> Previous </UIButton> </template>
<template #next> <UIButton variant="ghost" :disabled="page === totalPages" > Next <ChevronRightIcon class="w-5 h-5" /> </UIButton> </template> </UIPagination> </div></template>Component Composition
The UIPagination component works well with:
- UITable for data tables
- UISelect for page size selection
- UIButton for custom navigation
- UIInput for quick jumper
- UISpinner for loading states
- UITooltip for page information