Data Table
A powerful, feature-rich data table with server-side operations, filtering, sorting, pagination, row selection, column pinning, and keyboard navigation.
Overview
The DataTable is MeldUI’s most comprehensive component, built on TanStack Table for headless table logic with a fully styled UI layer. It’s a fully controlled component: state for sorting, filtering, and pagination is owned by the parent via three v-model bindings, and the parent triggers a data fetch whenever that state changes.
Architecture
DataTable runs TanStack in fully manual mode (manualSorting, manualFiltering, manualPagination). It never sorts, filters, or paginates rows itself — it just renders the page of data you give it and forwards user interactions through three independent emits:
v-model:sorting↔update:sorting—SortingStatev-model:filters↔update:filters—DataTableFilterStatev-model:pagination↔update:pagination—{ pageIndex, pageSize }
The recommended path is to bundle the three refs with useDataTableController, which also encapsulates the load-bearing rule that pagination must reset to page 0 on filter or sort change (with flush: 'sync' to keep the parent watcher firing exactly once per user action).
Key Features
- Stateless contract — three v-models, three update emits, no hidden internal state
- Server-side first — fully manual mode; the parent owns every fetch
- 8 filter types — text, select, multiselect, number, range, boolean, date, daterange
- Advanced filter mode — operator-based filtering (contains, equals, greaterThan, etc.)
- Column helpers — type-safe column definitions with
createColumnHelper - Cell renderers — pre-built formatters for badge, date, currency, number, boolean
- Row selection — checkbox selection with bulk actions
- Column pinning — sticky left/right columns
- Column resizing — drag-to-resize with onChange/onEnd modes
- Row expansion — master-detail pattern
- Keyboard navigation — full keyboard support
- Density modes — compact, comfortable, spacious
Installation
The DataTable is part of @meldui/vue. You also need @tanstack/vue-table as a peer dependency:
pnpm add @meldui/vue @tanstack/vue-table
Quick Start
<script setup lang="ts">
import { ref, watch } from 'vue'
import { DataTable, createColumnHelper, useDataTableController } from '@meldui/vue'
interface User {
id: string
name: string
email: string
role: string
}
const helper = createColumnHelper<User>()
const columns = [
helper.accessor('name', { title: 'Name', enableSorting: true }),
helper.accessor('email', { title: 'Email' }),
helper.accessor('role', { title: 'Role' }),
]
const { sorting, filters, pagination, state } = useDataTableController({ pageSize: 20 })
const data = ref<User[]>([])
const pageCount = ref(1)
async function fetchPage() {
const res = await api.get('/users', {
params: {
page: state.value.pagination.pageIndex + 1,
per_page: state.value.pagination.pageSize,
},
})
data.value = res.data
pageCount.value = res.meta.total_pages
}
watch(state, fetchPage, { deep: true })
fetchPage()
</script>
<template>
<DataTable
:columns="columns"
:data="data"
:page-count="pageCount"
enable-sorting
enable-pagination
v-model:sorting="sorting"
v-model:filters="filters"
v-model:pagination="pagination"
/>
</template>
Pages in this section
| Page | Description |
|---|---|
| Basic Usage | Simple table setup with sorting and pagination |
| Columns & Cells | Column helpers, cell renderers, and aggregations |
| Filtering | Filter types, advanced mode, and operators |
| Selection & Actions | Row selection and bulk actions |
| Column Pinning | Sticky left/right columns |
| Row Expansion | Master-detail pattern |
| Server-Side | Server params, response format, and URL state |
useDataTableController | Composable that bundles the three refs and reset rules |
| Recipes | Eight canonical wiring scenarios (internal, external, grid views, URL state) |