DataTable Component
The DataTable
component is a flexible and customizable table component built with Vue 3. It supports a sort-by event, custom headers and custom items.
Basic Usage
Import and use DataTable
in your Vue components:
vue
<template>
<DataTable :headers="headers" :items="items" />
</template>
<script setup>
import { DataTable } from '@robuust-digital/vue-components';
const headers = [
{ id: 1, key: 'name', label: 'Name', sortable: true },
{ id: 2, key: 'age', label: 'Age', sortable: true, align: 'right' },
{ id: 3, key: 'email', label: 'Email', sortable: false, align: 'left' },
];
const items = [
{ id: 1, name: 'John Doe', age: 28, email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', age: 34, email: 'jane@example.com' },
{ id: 3, name: 'Sam Green', age: 45, email: 'sam@example.com' },
];
</script>
John Doe | john@example.com | ||
Jane Smith | jane@example.com | ||
Sam Green | sam@example.com |
Props
Prop | Type | Default | Description |
---|---|---|---|
headers | Array | [] | Array of header objects defining the table columns |
items | Array | [] | Array of item objects representing the table rows |
noResultsText | String | 'No results found.' | Text to display when no items are available |
loadingText | String | 'Loading content...' | Text to display when the table is in a loading state |
striped | Boolean | false | Apply striped rows style |
spinning | Boolean | false | Display a loading spinner |
Slots
Headers Slot
Customize the table headers.
vue
<template>
<DataTable :headers="headers" :items="items">
<template #headers="{ headers }">
<th v-for="header in headers" :key="header.id">
{{ header.label }}
</th>
</template>
</DataTable>
</template>
Header Label Slot
Customize the header labels.
vue
<template>
<DataTable :headers="headers" :items="items">
<template #header-label="{ header, sortBy }">
<span class="custom-class-styling">{{ header.label }}</span>
<button type="button" v-if="header.sortable" @click="sortBy(header.key)">
<ArrowUpIcon />
<ArrowDownIcon />
</button>
</template>
</DataTable>
</template>
Items Slot
Customize the table rows.
vue
<template>
<DataTable :headers="headers" :items="items">
<template #items="{ item, index }">
<td v-for="(value, key) in item" :key="key">
{{ value }}
</td>
</template>
</DataTable>
</template>
Spinner Slot
Customize the loading spinner.
vue
<template>
<DataTable :headers="headers" :items="items" :spinning="true">
<template #spinner="{ spinning, label }">
<div v-if="spinning">
<CustomSpinnerIcon />
{{ label }}
</div>
</template>
</DataTable>
</template>
Examples
DataTable with Custom Headers
Name | Age | ||
---|---|---|---|
John Doe | john@example.com | ||
Jane Smith | jane@example.com | ||
Sam Green | sam@example.com |
Show code
vue
<template>
<DataTable :headers="headers" :items="items">
<template #headers="{ headers }">
<th v-for="header in headers" :key="header.id">
{{ header.label }}
</th>
</template>
</DataTable>
</template>
DataTable with Custom Items
Member | Status | Actions | |||
---|---|---|---|---|---|
4-uurs arrangement | 01-01-2024 | John Doe | € 10,15 | active | |
8-uurs arrangement | 01-05-2024 | Jane Doe | € 15,15 | pending | |
12-uurs arrangement | 01-03-2024 | Sarah Doe | € 20,15 | active | |
24-uurs arrangement | 01-02-2024 | Justin Doe | € 25,15 | active |
Show code
vue
<template>
<DataTable
:headers="headers"
:items="items"
striped
@table:sort-by="(sortBy) => console.log(sortBy)"
>
<template #items="{ item }">
<td>
<a
href="#"
class="hover:underline block"
>
{{ item.package }}
</a>
</td>
<td>
{{ item.date }}
</td>
<td>
<a
href="#"
class="flex gap-x-2 items-center hover:underline"
>
<img
:src="item.member.avatar"
:alt="item.member.name"
width="28"
height="28"
class="size-7 rounded-full shrink-0"
loading="lazy"
/>
<span class="font-medium">{{ item.member.name }}</span>
</a>
</td>
<td class="text-right">
{{ item.price }}
</td>
<td>
<Badge
:color="item.status === 'active' ? 'green' : 'yellow'"
:label="item.status"
size="sm"
/>
</td>
<td class="text-right">
<ButtonBase
label="Edit"
type="button"
icon-only
color="clear"
:icon="PencilSquareIcon"
size="sm"
/>
<ButtonBase
label="Delete"
type="button"
icon-only
color="clear"
:icon="TrashIcon"
size="sm"
/>
</td>
</template>
</DataTable>
</template>
<script setup>
import { DataTable, Badge, ButtonBase } from '@robuust-digital/vue-components';
import { TrashIcon, PencilSquareIcon } from '@heroicons/vue/16/solid';
const headers = [
{
id: 0, label: 'Package', key: 'package', sortable: true,
},
{
id: 1, label: 'Date', key: 'date', sortable: true,
},
{
id: 2, label: 'Member', key: 'member',
},
{
id: 3, label: 'Price', key: 'price', align: 'right', sortable: true,
},
{
id: 4, label: 'Status', key: 'status', align: 'left',
},
{
id: 5, label: 'Actions', key: 'actions', align: 'right',
},
];
const items = [
{
id: 1,
package: '4-uurs arrangement',
date: '01-01-2024',
status: 'active',
member: {
name: 'John Doe',
id: 0,
avatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=200&h=200&auto=format&fit=facearea&facepad=3&q=80',
},
price: '€ 10,15',
},
{
id: 2,
package: '8-uurs arrangement',
date: '01-05-2024',
status: 'pending',
member: {
name: 'Jane Doe',
id: 1,
avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200&h=200&auto=format&fit=facearea&facepad=3&q=80',
},
price: '€ 15,15',
},
{
id: 3,
package: '12-uurs arrangement',
date: '01-03-2024',
status: 'active',
member: {
name: 'Sarah Doe',
id: 1,
avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=200&h=200&auto=format&fit=facearea&facepad=3&q=80',
},
price: '€ 20,15',
},
{
id: 4,
package: '24-uurs arrangement',
date: '01-02-2024',
status: 'active',
member: {
name: 'Justin Doe',
id: 1,
avatar: 'https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?w=200&h=200&auto=format&fit=facearea&facepad=3&q=80',
},
price: '€ 25,15',
},
];
</script>
Customization with Tailwind CSS
To customize the DataTable
styles globally, extend your Tailwind configuration. Example:
javascript
// tailwind.config.js
export default {
theme: {
extend: {
components: (theme) => ({
table: {
// Available variables you can override:
'--rvc-table-head-border-color': theme('colors.slate.300'),
'--rvc-table-border-color': theme('colors.slate.200'),
'--rvc-table-border-style': 'solid',
'--rvc-table-border-width': theme('borderWidth.DEFAULT'),
'--rvc-table-head-bg-color': theme('colors.slate.200'),
'--rvc-table-bg-color': theme('colors.slate.50'),
'--rvc-table-font-size': '0.875rem',
'--rvc-table-head-font-size': '0.875rem',
'--rvc-table-head-font-weight': theme('fontWeight.medium'),
'--rvc-table-font-weight': theme('fontWeight.normal'),
'--rvc-table-padding-x': theme('padding.2'),
'--rvc-table-padding-y': theme('padding.3'),
'--rvc-table-white-space': 'nowrap',
'--rvc-table-line-height': '1.1',
'--rvc-table-spinner-size': theme('size.5'),
},
}),
},
},
};