NuGrid provides built-in pagination for dividing large datasets into manageable pages.
<script setup lang="ts">
import type { NuGridColumn } from '#nu-grid/types'
interface Item {
id: number
name: string
category: string
value: number
}
// Generate sample data
const data = ref<Item[]>(
Array.from({ length: 50 }, (_, i) => ({
id: i + 1,
name: `Item ${i + 1}`,
category: ['Electronics', 'Clothing', 'Books', 'Home'][i % 4]!,
value: Math.floor(Math.random() * 1000) + 10,
})),
)
const columns: NuGridColumn<Item>[] = [
{ accessorKey: 'id', header: 'ID', size: 60 },
{ accessorKey: 'name', header: 'Name', size: 120 },
{ accessorKey: 'category', header: 'Category', size: 120 },
{
accessorKey: 'value',
header: 'Value',
size: 100,
cell: ({ row }) => `$${row.original.value}`,
},
]
</script>
<template>
<div class="w-full">
<NuGrid
:data="data"
:columns="columns"
:paging="{
enabled: true,
pageSize: 10,
pageSizeSelector: [5, 10, 20, 50],
}"
:ui="{
base: 'w-full border-separate border-spacing-0',
thead: '[&>tr]:bg-elevated/50',
th: 'py-2 border-y border-default first:border-l last:border-r first:rounded-l-lg last:rounded-r-lg',
td: 'border-b border-default',
}"
/>
</div>
</template>
Enable pagination with the paging prop:
<template>
<!-- Simple enable with defaults -->
<NuGrid :data="data" :columns="columns" :paging="true" />
<!-- With options -->
<NuGrid
:data="data"
:columns="columns"
:paging="{
pageSize: 20,
pageSizeSelector: [10, 20, 50, 100],
}"
/>
</template>
interface NuGridPagingOptions {
enabled?: boolean
pageSize?: number
pageSizeSelector?: number[] | false
autoPageSize?: boolean
suppressPanel?: boolean
}
| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable pagination |
pageSize | number | 20 | Rows per page |
pageSizeSelector | number[] | false | [10, 20, 50, 100] | Page size options |
autoPageSize | boolean | false | Auto-fit rows to container |
suppressPanel | boolean | false | Hide built-in pagination UI |
Track pagination state with v-model:
<script setup lang="ts">
const pagination = ref({
pageIndex: 0,
pageSize: 20,
})
</script>
<template>
<NuGrid
v-model:pagination="pagination"
:data="data"
:columns="columns"
:paging="true"
/>
</template>
Customize available page sizes:
<template>
<!-- Custom options -->
<NuGrid
:data="data"
:columns="columns"
:paging="{
pageSize: 25,
pageSizeSelector: [25, 50, 100, 200],
}"
/>
<!-- Hide selector -->
<NuGrid
:data="data"
:columns="columns"
:paging="{
pageSize: 20,
pageSizeSelector: false,
}"
/>
</template>
Automatically calculate page size based on container height:
<template>
<div class="h-[500px]">
<NuGrid
:data="data"
:columns="columns"
:paging="{ autoPageSize: true }"
/>
</div>
</template>
The grid will automatically adjust the page size to fill the available space.
Hide the built-in panel and use your own:
<script setup lang="ts">
const gridRef = useTemplateRef('grid')
const pagination = ref({ pageIndex: 0, pageSize: 20 })
const totalPages = computed(() =>
Math.ceil(data.value.length / pagination.value.pageSize)
)
function goToPage(page: number) {
pagination.value.pageIndex = page
}
</script>
<template>
<NuGrid
ref="grid"
v-model:pagination="pagination"
:data="data"
:columns="columns"
:paging="{ suppressPanel: true }"
/>
<div class="mt-4 flex items-center justify-between">
<span>
Page {{ pagination.pageIndex + 1 }} of {{ totalPages }}
</span>
<div class="flex gap-2">
<UButton
:disabled="pagination.pageIndex === 0"
@click="goToPage(0)"
>
First
</UButton>
<UButton
:disabled="pagination.pageIndex === 0"
@click="goToPage(pagination.pageIndex - 1)"
>
Previous
</UButton>
<UButton
:disabled="pagination.pageIndex >= totalPages - 1"
@click="goToPage(pagination.pageIndex + 1)"
>
Next
</UButton>
<UButton
:disabled="pagination.pageIndex >= totalPages - 1"
@click="goToPage(totalPages - 1)"
>
Last
</UButton>
</div>
</div>
</template>
Navigate pages via the grid ref:
<script setup lang="ts">
const gridRef = useTemplateRef('grid')
function goToFirstPage() {
gridRef.value?.pagingGoToPage(0)
}
function goToLastPage() {
gridRef.value?.pagingGoToPage(-1) // -1 = last page
}
function goToPage(page: number) {
gridRef.value?.pagingGoToPage(page)
}
</script>
When pagination is enabled:
| Key | Action |
|---|---|
Ctrl/Cmd + Arrow Up | Previous page (with cmdArrows: 'paging') |
Ctrl/Cmd + Arrow Down | Next page (with cmdArrows: 'paging') |
Page Up | Previous page |
Page Down | Next page |
Enable paging keyboard mode:
<template>
<NuGrid
:data="data"
:columns="columns"
:paging="true"
:focus="{ cmdArrows: 'paging' }"
/>
</template>
Pagination works with grouped data:
<script setup lang="ts">
const grouping = ref(['category'])
</script>
<template>
<NuGrid
v-model:grouping="grouping"
:data="data"
:columns="columns"
:paging="{ pageSize: 20 }"
/>
</template>
Groups are expanded/collapsed across pages.
For server-side pagination, manage state externally:
<script setup lang="ts">
const pagination = ref({ pageIndex: 0, pageSize: 20 })
const totalRows = ref(0)
const data = ref([])
async function fetchPage() {
const response = await api.getItems({
page: pagination.value.pageIndex,
limit: pagination.value.pageSize,
})
data.value = response.items
totalRows.value = response.total
}
watch(pagination, fetchPage, { deep: true, immediate: true })
</script>
<template>
<NuGrid
v-model:pagination="pagination"
:data="data"
:columns="columns"
:paging="{ suppressPanel: true }"
:row-count="totalRows"
manual-pagination
/>
<!-- Custom pagination controls -->
</template>
<script setup lang="ts">
const gridRef = useTemplateRef('grid')
const data = ref(generateData(200)) // 200 items
const paginationOptions = computed(() => ({
enabled: true,
pageSize: 20,
pageSizeSelector: [10, 20, 50, 100],
}))
const currentPage = computed(() =>
(gridRef.value?.tableApi?.getState().pagination.pageIndex ?? 0) + 1
)
const totalPages = computed(() =>
gridRef.value?.tableApi?.getPageCount() ?? 1
)
</script>
<template>
<div class="space-y-4">
<div class="flex items-center justify-between">
<span class="text-sm text-muted">
Showing page {{ currentPage }} of {{ totalPages }}
({{ data.length }} total items)
</span>
<div class="flex gap-2">
<UButton
size="sm"
variant="outline"
@click="gridRef?.pagingGoToPage(0)"
>
First
</UButton>
<UButton
size="sm"
variant="outline"
@click="gridRef?.pagingGoToPage(currentPage - 2)"
>
Prev
</UButton>
<UButton
size="sm"
variant="outline"
@click="gridRef?.pagingGoToPage(currentPage)"
>
Next
</UButton>
<UButton
size="sm"
variant="outline"
@click="gridRef?.pagingGoToPage(-1)"
>
Last
</UButton>
</div>
</div>
<NuGrid
ref="grid"
:data="data"
:columns="columns"
:paging="paginationOptions"
/>
</div>
</template>