Skip to content

Data Table

DataTable combines Table with Pagination into a single server-side pagination component. It handles the layout and wires pagination events — you supply the data for the current page.

Basic usage

Tailwind v4
vue
<script setup>
import { ref } from 'vue'

const columns = [
  { key: 'name',     label: 'Name' },
  { key: 'status',   label: 'Status' },
  { key: 'location', label: 'Location' },
  { key: 'updated',  label: 'Last Updated', align: 'right' },
]

const page = ref(1)
const rows = ref([...]) // current page data only
const total = ref(87)   // total record count across all pages

function onPageChange(p) {
  page.value = p
  // fetch new data for page p
}
</script>

<template>
  <DataTable
    :columns="columns"
    :rows="rows"
    :total="total"
    :page="page"
    :per-page="20"
    @update:page="onPageChange"
  />
</template>

Custom cell slots

All Table slot patterns work inside DataTable:

vue
<DataTable :columns="columns" :rows="rows" :total="total" :page="page" @update:page="page = $event">
  <template #cell-status="{ row }">
    <Badge :variant="row.status === 'active' ? 'success' : 'neutral'">
      {{ row.status }}
    </Badge>
  </template>
</DataTable>

Loading state

vue
<DataTable
  :columns="columns"
  :rows="[]"
  :total="0"
  :page="1"
  :loading="fetching"
  @update:page="page = $event"
/>

Props

PropTypeDefaultDescription
columnsTableColumn[]Column definitions (see Table)
rowsRecord<string, unknown>[]Current page row data
totalnumberTotal records (all pages) — used to calculate page count
pagenumberCurrent page (1-indexed)
perPagenumber20Records per page
loadingbooleanfalseShow loading skeleton
emptystring'No results'Empty state message

Events

EventPayloadDescription
update:pagenumberEmitted when the user navigates to a new page

Slots

Inherits all Table slots — use #cell-<key> to customize any column cell.

Private — Jetpack Labs internal use only