6.6 KiB
DataTable Migration Guide
Summary of Changes
The DataTable component has been updated to follow shadcn-vue architecture patterns using TanStack Table v8. This provides better flexibility, more features, and follows industry-standard patterns.
What's New
✅ Components Created/Updated
DataTableNew2.vue- New main component with shadcn-vue architectureDataTableColumnHeader.vue- Already good, uses lucide-vue-next iconsDataTablePagination.vue- Already follows shadcn-vue patternsDataTableViewOptions.vue- Already follows shadcn-vue patternsDataTableToolbar.vue- Already exists with advanced featurescolumns-example.js- Column definition examplesREADME.md- Comprehensive documentationDataTableExample.vue- Working example page
✅ Utilities Added
valueUpdater()inlib/utils.js- Helper for TanStack Table state management
Key Improvements
1. FlexRender Integration
Now properly uses TanStack Table's FlexRender for column headers and cells:
<FlexRender
:render="cell.column.columnDef.cell"
:props="cell.getContext()"
/>
2. Better Column Definitions
Supports both simple and advanced formats:
Simple:
{ key: 'name', label: 'Name', sortable: true }
Advanced:
{
accessorKey: 'name',
header: ({ column }) => h(DataTableColumnHeader, { column, title: 'Name' }),
cell: ({ row }) => h('div', {}, row.getValue('name')),
}
3. Enhanced Features
- ✅ Row selection with checkboxes
- ✅ Column visibility toggle
- ✅ Advanced filtering
- ✅ Better loading/empty states
- ✅ Custom cell slots
- ✅ Flexible toolbar
4. Better State Management
Uses valueUpdater() helper for proper Vue reactivity with TanStack Table:
onSortingChange: (updater) => valueUpdater(updater, sorting)
Migration Steps
Step 1: Update Imports
Before:
import DataTable from '@/Components/DataTable/DataTable.vue';
After:
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
Step 2: Update Props
Before:
<DataTable
:rows="clients.data"
:columns="columns"
:meta="clients.meta"
/>
After:
<DataTable
:data="clients.data"
:columns="columns"
:meta="clients.meta"
route-name="clients.index"
/>
Main prop changes:
rows→data- Add
route-namefor server-side pagination
Step 3: Column Definitions
Your existing simple column format still works:
const columns = [
{ key: 'id', label: 'ID', sortable: true },
{ key: 'name', label: 'Name', sortable: true },
];
But you can now use advanced format for more control:
import { h } from 'vue';
import DataTableColumnHeader from '@/Components/DataTable/DataTableColumnHeader.vue';
const columns = [
{
accessorKey: 'name',
header: ({ column }) => h(DataTableColumnHeader, { column, title: 'Name' }),
cell: ({ row }) => h('div', { class: 'font-medium' }, row.getValue('name')),
},
];
Step 4: Custom Cell Rendering
Before: Required editing component After: Use slots!
<DataTable :columns="columns" :data="data">
<template #cell-status="{ value, row }">
<Badge :variant="value === 'active' ? 'default' : 'secondary'">
{{ value }}
</Badge>
</template>
</DataTable>
Backward Compatibility
The old DataTable components are still available:
DataTable.vue- Your current enhanced versionDataTableServer.vue- Your server-side versionDataTableOld.vue- Original version
You can migrate pages gradually. Both old and new can coexist.
Example Migration
Before (Client/Index.vue)
<script setup>
import DataTable from '@/Components/DataTable/DataTable.vue';
const props = defineProps({
clients: Object,
filters: Object,
});
const columns = [
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email', sortable: true },
];
</script>
<template>
<DataTable
:rows="clients.data"
:columns="columns"
:meta="clients.meta"
:search="filters.search"
:sort="filters.sort"
route-name="clients.index"
/>
</template>
After (Using DataTableNew2)
<script setup>
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
const props = defineProps({
clients: Object,
filters: Object,
});
const columns = [
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email', sortable: true },
{ key: 'status', label: 'Status', sortable: false },
];
</script>
<template>
<DataTable
:data="clients.data"
:columns="columns"
:meta="clients.meta"
:search="filters.search"
:sort="filters.sort"
route-name="clients.index"
filter-column="email"
filter-placeholder="Search clients..."
:only-props="['clients']"
>
<!-- Add custom cell rendering -->
<template #cell-status="{ value }">
<Badge :variant="value === 'active' ? 'default' : 'secondary'">
{{ value }}
</Badge>
</template>
</DataTable>
</template>
Testing Your Migration
-
Check the example page:
Visit: /examples/datatable(You'll need to add a route for this)
-
Test features:
- ✅ Sorting (click column headers)
- ✅ Filtering (use search input)
- ✅ Pagination (navigate pages)
- ✅ Row selection (if enabled)
- ✅ Column visibility (View button)
-
Check browser console:
- No errors
- Events firing correctly
Common Issues
Issue: "FlexRender is not defined"
Solution: Make sure you imported it:
import { FlexRender } from '@tanstack/vue-table';
Issue: Column not sorting
Solution: Make sure sortable: true is set:
{ key: 'name', label: 'Name', sortable: true }
Issue: Server-side not working
Solution: Provide both meta and route-name:
<DataTable
:data="data"
:meta="meta"
route-name="your.route.name"
/>
Issue: Custom cells not rendering
Solution: Use the correct slot name format:
<template #cell-columnKey="{ value, row }">
<!-- Your content -->
</template>
Need Help?
- Check
README.mdfor detailed documentation - Look at
columns-example.jsfor column patterns - Review
DataTableExample.vuefor working examples - Check TanStack Table docs: https://tanstack.com/table/v8
Rollback Plan
If you encounter issues, you can always use the old components:
import DataTable from '@/Components/DataTable/DataTable.vue';
// or
import DataTableServer from '@/Components/DataTable/DataTableServer.vue';
Nothing breaks your existing code!