9.4 KiB
9.4 KiB
DataTable Component - Usage Guide
This DataTable component follows the shadcn-vue architecture and uses TanStack Table v8 for powerful table functionality.
Features
- ✅ Client-side and server-side pagination
- ✅ Sorting (single column)
- ✅ Filtering/Search
- ✅ Row selection
- ✅ Column visibility toggle
- ✅ Customizable column definitions
- ✅ Loading states
- ✅ Empty states
- ✅ Flexible toolbar
- ✅ Cell-level customization via slots
- ✅ Responsive design
- ✅ Laravel Inertia integration
Basic Usage
Simple Format (Recommended for basic tables)
<script setup>
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
const columns = [
{ key: 'id', label: 'ID', sortable: true },
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email', sortable: true },
{ key: 'status', label: 'Status' },
];
const data = ref([
{ id: 1, name: 'John Doe', email: 'john@example.com', status: 'Active' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'Inactive' },
]);
</script>
<template>
<DataTable :columns="columns" :data="data" />
</template>
Advanced Format (Full TanStack Table power)
<script setup>
import { h } from 'vue';
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
import { Badge } from '@/Components/ui/badge';
import { columns } from './columns'; // Import from separate file
const data = ref([...]);
</script>
<template>
<DataTable :columns="columns" :data="data" />
</template>
See columns-example.js for comprehensive column definition examples.
Props
Data Props
columns(Array, required) - Column definitions (simple or TanStack format)data(Array, default: []) - Array of data objectsmeta(Object, default: null) - Laravel pagination meta for server-sideloading(Boolean, default: false) - Loading state
Server-side Props
routeName(String) - Laravel route name for server-side requestsrouteParams(Object) - Additional route parameterspageParamName(String, default: 'page') - Custom page parameter nameonlyProps(Array) - Inertia.js only propspreserveState(Boolean, default: true)preserveScroll(Boolean, default: true)
Sorting & Filtering
sort(Object, default: {key: null, direction: null})search(String, default: '')filterColumn(String) - Column to filter onfilterPlaceholder(String, default: 'Filter...')
Pagination
showPagination(Boolean, default: true)pageSize(Number, default: 10)pageSizeOptions(Array, default: [10, 25, 50, 100])
Features
enableRowSelection(Boolean, default: false)showToolbar(Boolean, default: true)striped(Boolean, default: false)hoverable(Boolean, default: true)rowKey(String|Function, default: 'id')
Empty State
emptyText(String, default: 'No results.')emptyIcon(String|Object|Array)emptyDescription(String)
Events
@update:search- Emitted when search changes@update:sort- Emitted when sort changes@update:page- Emitted when page changes@update:pageSize- Emitted when page size changes@row:click- Emitted when row is clicked@selection:change- Emitted when selection changes
Client-side Example
<script setup>
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
const columns = [
{ key: 'id', label: 'ID', sortable: true },
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email', sortable: true },
];
const data = ref([
// Your data here
]);
</script>
<template>
<DataTable
:columns="columns"
:data="data"
:page-size="10"
filter-column="email"
filter-placeholder="Filter emails..."
enable-row-selection
/>
</template>
Server-side Example (Laravel Inertia)
Controller
public function index(Request $request)
{
$query = Client::query();
// Search
if ($request->search) {
$query->where('name', 'like', "%{$request->search}%")
->orWhere('email', 'like', "%{$request->search}%");
}
// Sort
if ($request->sort && $request->direction) {
$query->orderBy($request->sort, $request->direction);
}
$clients = $query->paginate($request->per_page ?? 10);
return Inertia::render('Clients/Index', [
'clients' => $clients,
'filters' => $request->only(['search', 'sort', 'direction']),
]);
}
Vue Component
<script setup>
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
const props = defineProps({
clients: Object,
filters: Object,
});
const columns = [
{ key: 'id', label: 'ID', sortable: true },
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email', sortable: true },
];
</script>
<template>
<DataTable
:columns="columns"
:data="clients.data"
:meta="clients.meta"
:search="filters.search"
:sort="{ key: filters.sort, direction: filters.direction }"
route-name="clients.index"
filter-column="email"
filter-placeholder="Search clients..."
:only-props="['clients']"
/>
</template>
Custom Cell Rendering
Using Slots
<template>
<DataTable :columns="columns" :data="data">
<!-- Custom cell for status column -->
<template #cell-status="{ value, row }">
<Badge :variant="value === 'active' ? 'default' : 'secondary'">
{{ value }}
</Badge>
</template>
<!-- Custom cell for actions -->
<template #cell-actions="{ row }">
<Button @click="editRow(row)">Edit</Button>
</template>
</DataTable>
</template>
Using Column Definitions
import { h } from 'vue';
import { Badge } from '@/Components/ui/badge';
export const columns = [
{
accessorKey: 'status',
header: 'Status',
cell: ({ row }) => {
const status = row.getValue('status');
return h(Badge, {
variant: status === 'active' ? 'default' : 'secondary'
}, () => status);
},
},
];
Custom Toolbar
The new toolbar is simplified and follows shadcn-vue patterns:
<template>
<DataTable
:columns="columns"
:data="data"
filter-column="email"
filter-placeholder="Search emails..."
>
<!-- Add custom filter controls -->
<template #toolbar-filters="{ table }">
<select
@change="table.getColumn('status')?.setFilterValue($event.target.value)"
class="h-8 rounded-md border px-3"
>
<option value="">All Status</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
</template>
<!-- Add custom action buttons -->
<template #toolbar-actions="{ table }">
<Button @click="exportData">Export</Button>
<Button @click="addNew">Add New</Button>
</template>
</DataTable>
</template>
Or completely replace the toolbar:
<template>
<DataTable :columns="columns" :data="data" :show-toolbar="false">
<template #toolbar="{ table }">
<div class="flex items-center justify-between mb-4">
<Input
:model-value="table.getColumn('email')?.getFilterValue()"
@update:model-value="table.getColumn('email')?.setFilterValue($event)"
placeholder="Filter emails..."
class="max-w-sm"
/>
<div class="flex gap-2">
<Button @click="exportData">Export</Button>
<DataTableViewOptions :table="table" />
</div>
</div>
</template>
</DataTable>
</template>
Row Selection
<script setup>
import { ref } from 'vue';
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
const selectedRows = ref([]);
function handleSelectionChange(keys) {
selectedRows.value = keys;
console.log('Selected rows:', keys);
}
</script>
<template>
<DataTable
:columns="columns"
:data="data"
enable-row-selection
@selection:change="handleSelectionChange"
/>
<div v-if="selectedRows.length">
Selected {{ selectedRows.length }} row(s)
</div>
</template>
Row Click Handler
<script setup>
function handleRowClick(row, index) {
console.log('Clicked row:', row);
// Navigate or perform action
router.visit(route('clients.show', row.id));
}
</script>
<template>
<DataTable
:columns="columns"
:data="data"
@row:click="handleRowClick"
/>
</template>
Tips
- Column Keys: Always use consistent keys/accessorKeys across your data
- Server-side: Always provide
metaandrouteNameprops together - Performance: For large datasets, use server-side pagination
- Styling: Use column
classproperty for custom styling - Slots: Prefer slots for complex cell rendering over h() functions
Migration from Old DataTable
Before (Old API)
<DataTable
:rows="clients.data"
:columns="columns"
:meta="clients.meta"
/>
After (New API)
<DataTableNew2
:data="clients.data"
:columns="columns"
:meta="clients.meta"
route-name="clients.index"
/>
Main changes:
rows→data- Added
route-nameprop for server-side - More consistent prop naming
- Better TypeScript support
- More flexible column definitions
Component Files
DataTableNew2.vue- Main table componentDataTableColumnHeader.vue- Sortable column headerDataTablePagination.vue- Pagination controlsDataTableViewOptions.vue- Column visibility toggleDataTableToolbar.vue- Toolbar componentcolumns-example.js- Column definition examples