MeldUI

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:sortingupdate:sortingSortingState
  • v-model:filtersupdate:filtersDataTableFilterState
  • v-model:paginationupdate: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

PageDescription
Basic UsageSimple table setup with sorting and pagination
Columns & CellsColumn helpers, cell renderers, and aggregations
FilteringFilter types, advanced mode, and operators
Selection & ActionsRow selection and bulk actions
Column PinningSticky left/right columns
Row ExpansionMaster-detail pattern
Server-SideServer params, response format, and URL state
useDataTableControllerComposable that bundles the three refs and reset rules
RecipesEight canonical wiring scenarios (internal, external, grid views, URL state)