BaseDataTable
A responsive data table component built on native HTML <table>. Supports single/multiple row selection, expandable rows, loading states, striped rows, and custom cell rendering via named slots.
Basic Usage
Demo
| Name | Role | Status | Joined |
|---|---|---|---|
| Alice Johnson | Designer | Active | 2023-01-15 |
| Bob Smith | Engineer | Active | 2022-07-20 |
| Carol Williams | Product | Away | 2023-03-08 |
| David Brown | Engineer | Active | 2021-11-30 |
| Eva Martinez | Designer | Inactive | 2024-01-01 |
Multiple Selection
Multiple Selection
| Name | Role | Status | Joined | |
|---|---|---|---|---|
| Alice Johnson | Designer | Active | 2023-01-15 | |
| Bob Smith | Engineer | Active | 2022-07-20 | |
| Carol Williams | Product | Away | 2023-03-08 | |
| David Brown | Engineer | Active | 2021-11-30 | |
| Eva Martinez | Designer | Inactive | 2024-01-01 |
Selected: None
Striped Rows + Loading
Striped + Loading
| Name | Role | Status | Joined |
|---|---|---|---|
Custom Cell Rendering
Use slotName on a column to render custom content in that cell:
vue
<BaseDataTable :items="items" :columns="columns">
<template #status="{ data }">
<span
class="badge"
:class="data.status === 'Active' ? 'badge-green' : 'badge-gray'"
>
{{ data.status }}
</span>
</template>
</BaseDataTable>Define slotName on the column definition:
ts
const columns = [
{ field: 'name', header: 'Name' },
{ field: 'status', header: 'Status', slotName: 'status' },
]Props
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items | Record<string, unknown>[] | [] | Array of row data objects. Each row should have a unique id field. |
| columns | ColumnDef[] | [] | Column definitions. See ColumnDef interface below. |
| loading | boolean | false | Shows a centered spinner and hides row data. |
| rows | number | 10 | Number of rows per page (for pagination, not yet implemented natively). |
| selectionMode | 'single' | 'multiple' | undefined | undefined | Enables row selection. 'multiple' shows checkboxes, 'single' shows radio buttons. |
| selectedItems | Record<string, unknown>[] | [] | Currently selected rows. Use alongside @selection-change. |
| stripedRows | boolean | false | Alternates row background colors for easier scanning. |
| emptyMessage | string | 'No data available' | Message shown when items array is empty and not searching. |
| searchEmptyMessage | string | 'No results found' | Message shown when items is empty and isSearching is true. |
| isSearching | boolean | false | When true, uses searchEmptyMessage for the empty state. |
| enableRowDblClick | boolean | false | Enables double-click events on rows. |
| expanderCondition | (row) => boolean | undefined | Function that returns whether a row should show the expander button. |
ColumnDef
ts
interface ColumnDef {
field: string // Property name from the row object
header: string // Column header text
slotName?: string // Named slot for custom cell rendering
style?: string | Record<string, string> // CSS styles for the column
sortable?: boolean // Reserved (not implemented)
frozen?: boolean // Reserved (not implemented)
}Emits
Emits
| Event | Payload | Description |
|---|---|---|
| row-click | unknown | Emitted 300ms after a single click on a row (debounced to avoid conflict with dblclick). |
| row-dblclick | unknown | Emitted on double-click. Requires enableRowDblClick to be true. |
| selection-change | unknown | Emitted when row selection changes. Returns the full updated selection array. |
Slots
Slots
| Slot | Scope | Description |
|---|---|---|
[slotName] | { data: row } | Custom cell content. Name must match slotName in the column definition. |
expansion | { data: row } | Expandable row content. Presence of this slot automatically adds an expander column. |