A flexible data list component for Vue 3 with sorting, filtering, row interactions, and optional CSV/XLSX export.
The List component uses floating-vue for tooltip functionality. This is included as a dependency and works out of the box—no additional setup required beyond standard component installation.
| Property | Type | Default | Description |
|---|---|---|---|
columns |
ListColumn[] |
required | Column definitions for rendering and behavior |
data |
ListRowData[] |
required | Row data source |
actions |
ListActionProps[] |
undefined |
Header actions rendered on the right side |
CSVDownload |
string |
undefined |
Enables CSV export and controls output file name |
XLSXDownload |
string |
undefined |
Enables XLSX export and controls output file name |
filter |
{ placeholder?: string } |
undefined |
Enables filter input in the header |
loading |
boolean |
false |
Shows loading state overlay |
emptyMessage |
string |
'No data available' |
Message shown when no rows are visible |
presentation |
'default' \| 'minimal' |
'default' |
Visual density/style |
width |
string |
'100%' |
Outer component width |
interface ListColumn {
key: string
label: string
type?: 'text' | 'number' | 'date' | 'datetime' | 'time' | 'action' | 'checkbox' | 'icon' | 'email'
align?: 'left' | 'center' | 'right'
sortable?: boolean
filterable?: boolean
width?: string
minWidth?: string
maxWidth?: string
cellClasses?: Record<string, (value: any) => boolean>
headerTooltip?: string
cellTooltip?: boolean
}
key: Unique identifier for the column; must match a property in row datalabel: Display name shown in the table headertype: Column data type affecting filtering, sorting, and rendering
text — Plain text, default typenumber — Numeric values with numeric sortingdate — Date values (formatted and sorted as dates)datetime — Date and time valuestime — Time-only valuesemail — Email addresses (rendered as mailto links)checkbox — Interactive checkbox fieldsaction — Action buttons for row operationsicon — Icon display with optional coloralign: Text alignment (left, center, right)sortable: Whether clicking the header sorts by this columnfilterable: Whether this column is included in text filter searcheswidth / minWidth / maxWidth: CSS sizing properties (e.g., '100px', '10rem')cellClasses: Function map for conditional CSS classes on cellsheaderTooltip: Tooltip text shown on header hover (uses floating-vue)cellTooltip: If true, cells show their formatted value on hover (type-aware formatting)In addition to your own row fields, these reserved helpers are supported:
| Field | Type | Description |
|---|---|---|
excludeFromSort |
boolean |
Keeps row out of sort operations |
excludeFromFilter |
boolean |
Keeps row visible even while filtering |
fixed |
'top' \| 'bottom' |
Pins excluded rows at top or bottom |
selected |
boolean |
Adds selected row style |
class |
string |
Adds list__row--{class} CSS modifier |
| Event | Payload | Description |
|---|---|---|
row-click |
(row: any, index: number) |
Emitted when a row is clicked |
row-dblclick |
(row: any, index: number) |
Emitted when a row is double-clicked |
download |
({ type: 'csv' \| 'xlsx'; fileName: string }) |
Emitted after export is triggered |
| Slot | Description |
|---|---|
header_extras |
Renders custom content in the header, between filter and actions |
| Method | Description |
|---|---|
focus() |
Focuses the filter input |
blur() |
Blurs the filter input |
clearFilter() |
Clears the current filter text |
The List component supports tooltips in two ways:
Set headerTooltip on a column to show a tooltip when hovering over the column header:
{
key: 'email',
label: 'Email',
headerTooltip: 'Contact email address'
}
Set cellTooltip: true on a column to show the cell’s formatted value in a tooltip on hover:
{
key: 'joined',
label: 'Joined',
type: 'date',
cellTooltip: true // Shows formatted date on hover
}
Cell tooltips automatically format values according to their column type:
text, number, email: Raw valuedate: Formatted using configured date localedatetime: Formatted using configured datetime localetime: Formatted using configured time localeList action buttons can also show tooltips via the tooltip property:
{
id: 'edit',
label: 'Edit',
icon: 'edit',
tooltip: 'Edit user details',
onActionClick: (row) => { /* ... */ }
}
3 characters.250ms.filterable: true are searched.excludeFromFilter: true are always shown regardless of the current filter value.filterable columns):
text, email: case-insensitive substring match against the string value.number: substring match against the string representation of the value.date: case-insensitive substring match against the formatted date string.datetime: case-insensitive substring match against the formatted datetime string.checkbox: matches against 'yes' (when modelValue is truthy) or 'no' (when falsy).time, action, icon, and all other types: not matched — these column types do not contribute to filter matches.date, datetime, time: parsed date comparison using Date.getTime().number: numeric subtraction comparison.checkbox: boolean comparison using modelValue.text, email): locale-aware case-insensitive string comparison.excludeFromSort rows are removed from the main sort and repositioned according to their fixed value. A row with excludeFromSort: true must also set fixed: 'top' or fixed: 'bottom' to remain in the rendered output; unanchored excluded rows are silently omitted.checkbox, icon, action).actions, CSVDownload, or XLSXDownload is present.<template>
<List
:columns="columns"
:data="rows"
:actions="headerActions"
:filter="{ placeholder: 'Search users...' }"
CSVDownload="users"
XLSXDownload="users"
@row-click="onRowClick"
@row-dblclick="onRowDoubleClick"
@download="onDownload"
width="500px"
>
<template #header_extras>
<div>Total users: </div>
</template>
</List>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { List } from '@a-vision/vue-input-components'
import type {
ListColumn,
ListRowData,
ListActionProps,
} from '@a-vision/vue-input-components'
const headerActions = ref<ListActionProps[]>([
{
id: 'new-user',
label: 'New user',
icon: 'add',
onActionClick: () => console.log('Create user'),
},
])
const columns: ListColumn[] = [
{
key: 'name',
label: 'Name',
type: 'text',
sortable: true,
filterable: true,
cellTooltip: true,
},
{
key: 'email',
label: 'Email',
type: 'email',
sortable: true,
filterable: true,
headerTooltip: 'Contact email address',
},
{
key: 'joined',
label: 'Joined',
type: 'date',
sortable: true,
cellTooltip: true,
},
{ key: 'actions', label: 'Actions', type: 'action', align: 'right', width: '10rem' },
]
const rows = ref<ListRowData[]>([
{
name: 'John Doe',
email: 'john@example.com',
joined: '2024-03-15',
actions: [
{
id: 'edit',
label: 'Edit',
icon: 'edit',
tooltip: 'Edit user information',
onActionClick: (row) => console.log('Edit', row)
},
{
id: 'delete',
label: 'Delete',
icon: 'trash',
tooltip: 'Delete this user',
onActionClick: (row) => console.log('Delete', row),
},
],
},
])
const onRowClick = (row: any, index: number) => console.log('row-click', row, index)
const onRowDoubleClick = (row: any, index: number) => console.log('row-dblclick', row, index)
const onDownload = (payload: { type: 'csv' | 'xlsx'; fileName: string }) => console.log(payload)
</script>