DataTable
A data table with semantic cells, column filtering, sorting, selection, and expandable rows.
Usage
Basic
Semantic type values provide numeric sorting, tag pills, and local calendar dates; filter: true adds the matching header filter.
Sorting
Number and date columns sort on their own, other columns opt in with sortable; defaultSort sets the starting order, and sortCycle decides whether a third click unsorts.
Filtering
filter: true gives each column the filter its type calls for: text search, tag picks, a number range, or date presets; a filter-<key> slot swaps in a panel of your own, and v-model:filter hands the state to the parent.
Row Selection
selectable adds a selection column; v-model:selected-keys syncs the selected rows.
Expandable Rows
expandable adds a leading toggle column; the #expanded slot renders the detail under a row.
Adaptive Column Widths
A nowrap column without a declared width hugs its content and the others share what is left; the action column pins right by default, and the table scrolls once nothing fits.
Loading States
loadingVariant picks a veil, skeleton rows, or a shimmer; skeleton and shimmer draw placeholder rows only while there are none, and a refresh keeps the existing rows.
Empty State
The #empty slot replaces the empty state of a table with no rows, with room for an explanation and an action; to change only the text, pass emptyText.
Records Table
A wide layout with a pinned header and footer, a frozen first column, and selection highlighting; cells compose TxTag, TxDotIndicator, and TxCellLink.
Data Operations Panel
TxPagination pages the list, and TxSkeleton / TxLayoutSkeleton preview the loading state.
Best Practices
- Pass a stable
rowKeyfor business lists; to keep selection across pages, driveselectedKeyswith business ids, not default indexes. - For server-loaded lists, use
loadingVariant="skeleton"or"shimmer"withskeletonRowsset to the page size; keep the defaultoverlayfor short local waits. - Let content size the columns: a nowrap column hugs its content with no declared width, and a long wrapping column takes a
minWidthas the floor it wraps to. - Fixed-column offsets are measured from the rendered widths; give numeric
widths only when several columns pin to one side, so the first frame and server render line up. Keep one horizontal scroller:scrollX, or an outeroverflow-x: auto. - A pinned header or footer needs
maxHeightor a scrolling ancestor; don't nest the table inTxScroll's default mode, whose transform scrolling disables sticky. - Sort on comparable fields such as timestamps or ranks, never on formatted relative-time text.
- Use
filterOnClient=falsefor remote filtering and handlefilterChangealongside pagination, passing tag-option row counts ascountinfilterOptions; controlledfilterremains the parent's state. - The filter controls speak English by default; localize them through
labels, whose keysDATA_TABLE_DEFAULT_LABELSlists. - A
datecolumn interpretsYYYY-MM-DDas a local calendar day. Adatetimecolumn preserves the instant of timezone-qualified values;todayends at the next local midnight, including daylight-saving transitions.
API Reference
Props
| Name | Type | Default | Description |
|---|---|---|---|
columns | DataTableColumn[] | [] | Column config. |
data | any[] | [] | Data source. |
rowKey | keyof T | (row: T, index: number) => string | number | index | Unique row key. |
loading | boolean | false | Loading state. |
loadingVariant | 'overlay' | 'skeleton' | 'shimmer' | 'overlay' | overlay veils the table with a spinner; skeleton draws placeholder rows, or only a bar when rows exist; shimmer sweeps a band of light across the placeholder rows or the existing ones. |
skeletonRows | number | 5 | Placeholder rows skeleton and shimmer draw before the first data lands; match the page size so nothing moves. A table whose host sets its height fills it to the bottom. |
emptyText | string | 'No data' | Empty text. |
striped | boolean | false | Zebra rows. |
bordered | boolean | false | Show borders. |
hover | boolean | true | Hover highlight. |
interactiveRows | boolean | false | Makes rows focusable so Enter / Space fire rowClick; on automatically with a rowClick listener. |
selectable | boolean | false | Adds a selection column. |
selectedKeys | Array<string | number> | [] | Keys of the selected rows. |
expandable | boolean | false | Adds a leading toggle column; an expanded row renders a detail row beneath it. |
defaultExpandedKeys | Array<string | number> | [] | Initial expanded rows when uncontrolled; expandedKeys wins if both are passed. |
expandedKeys | Array<string | number> | - | Controlled expanded rows, bound with v-model:expanded-keys. |
rowExpandable | (row, index) => boolean | - | Per-row gate for expanding; a rejected row keeps an empty leading cell. |
expandLabel | string | 'Expand row' | Accessible name of a closed toggle. |
collapseLabel | string | 'Collapse row' | Accessible name of an open toggle. |
defaultSort | { key: string; order: 'asc' | 'desc' | null } | null | Initial sort when uncontrolled; pass either this or sort. |
sort | { key: string; order: 'asc' | 'desc' | null } | null | - | Controlled sort; null means unsorted. |
sortOnClient | boolean | true | Sorts locally; set false for remote sorting, which only emits. |
sortCycle | 'tri' | 'bi' | 'tri' | tri: ascending → descending → unsorted; bi alternates and never unsorts. |
tableLayout | 'auto' | 'fixed' | 'auto' | Native table-layout; use fixed when column widths must stay stable. |
nowrap | boolean | false | Prevents wrapping in every header and cell. |
maxHeight | string | number | - | Caps the height and scrolls the table vertically; what sticky rows stick to. |
scrollX | boolean | false | Scrolls horizontally inside the component; for wide tables with fixed columns. |
stickyHeader | boolean | false | Pins the header row. |
stickyFooter | boolean | false | Pins the summary row. |
rowClass | (row, index) => string | string[] | Record<string, boolean> | - | Extra classes per row, such as a tint by state. |
highlightSelected | boolean | false | Tints selected rows. |
defaultFilter | DataTableFilterState | {} | Initial filter values in uncontrolled mode. |
filter | DataTableFilterState | - | Controlled values by column key; bind with v-model:filter. |
filterOnClient | boolean | true | Filters rows locally; false delegates row retrieval to the caller. |
autoStickyActions | boolean | true | Defaults action columns to the right fixed edge; an explicit column fixed takes precedence. |
labels | Partial<DataTableLabels> | - | Text of the filter controls; pass only the keys to replace, the rest keep their English defaults. |
Events
| Event | Payload | Description |
|---|---|---|
update:selectedKeys | (keys) | Selection update. |
selectionChange | (keys) | Selection change. |
update:expandedKeys | (keys) | Expansion update; fires in controlled and uncontrolled modes. |
expand | ({ row, index, expanded }) | A row was expanded or collapsed. |
sortChange | (sort) | Sort change. |
update:sort | (sort) | Sort change; fires in controlled and uncontrolled modes. |
update:filter | (filter) | Filter values changed; fires in controlled and uncontrolled modes. |
filterChange | (filter) | Filter changes for client or remote filtering. |
rowClick | ({ row, index }) | Row click. |
Slots
| Name | Description |
|---|---|
header-<columnKey> | Custom header; receives { column, sorted, order, toggle }, where toggle advances the sort cycle. |
cell-<columnKey> | Custom cell; receives { row, column, value, index }. |
filter-<columnKey> | Custom filter panel; receives { column, filterValue, setFilter, clearFilter, close }, where close closes the panel. |
expanded | Detail of an expanded row, spanning every column; receives { row, index }. |
footer | The whole summary row of your own <td>s, which can span columns. Any footer slot renders a <tfoot>. |
footer-<columnKey> | One summary cell per column; receives { column, data }. footer wins when both exist. |
empty | Empty state when there are no rows and loading=false. |
DataTableColumn
| Field | Type | Description |
|---|---|---|
key | string | Column key. |
title | string | Header title. |
type | 'text' | 'number' | 'datetime' | 'date' | 'tag' | 'source' | 'actions' | Semantic display, sort, and filter behavior; cell slots and format take precedence. |
dataIndex | string | Data field. |
width | string | number | Column width. Left out, a nowrap column hugs its content and the others share what is left. |
minWidth | string | number | Minimum column width. |
maxWidth | string | number | Maximum column width. |
auto | boolean | Forces the column width to auto. |
fixed | boolean | 'left' | 'right' | Sticky side; true means 'left'. Offsets are measured from the rendered widths, and left ones include the toggle and selection columns. |
nowrap | boolean | Prevents wrapping in this column. |
align | 'left' | 'center' | 'right' | Alignment. |
sortable | boolean | Sortable. |
sorter | (a, b) => number | Custom sorter. |
filter | boolean | Adds a type-aware header filter; off by default. |
filterOptions | DataTableFilterOption[] | Custom tag-filter options containing label, value, and optional tone and count (the row count shown beside the option). |
format | (value, row, index) => string | Cell formatter. |
headerClass | string | Header class. |
cellClass | string | Cell class. |
DataTableLabels
| Key | Default | Description |
|---|---|---|
filter | 'Filter {column}' | Accessible name of a filter button; {column} becomes the column title. |
filterAll | 'All' | Option that clears a tag filter. |
filterAnyTime | 'Any time' | Option that clears a date filter. |
filterToday | 'Today' | Date preset: today. |
filterLast3Days | 'Last 3 days' | Date preset: the last 3 days. |
filterLast7Days | 'Last 7 days' | Date preset: the last 7 days. |
filterLast30Days | 'Last 30 days' | Date preset: the last 30 days. |
filterSearch | 'Search' | Placeholder of the text filter and of a long tag list's search field. |
filterMin | 'Min' | Lower bound of a number range. |
filterMax | 'Max' | Upper bound of a number range. |
filterReset | 'Reset' | Clears a number range. |
filterApply | 'Done' | Closes a number range. |
Overview
- Passing
sortorexpandedKeys(evennullor[]) makes it controlled: the table only emits updates and renders what the parent sends back. filteralso makes filtering controlled. Tags accept one value or multiple values, numbers accept{ min, max }, and dates accepttoday,3d,7d,30d, or timestamp{ start, end }values. Text columns match a case-insensitive substring.- When a tag filter gathers its options from the rows, client filtering counts the rows behind each one; at 8 options the panel gains a search field.
- Sortable headers carry
scope="col"andaria-sort; click, Enter, and Space step throughsortCycle. - On a partial selection the select-all box is
indeterminate(aria-checked="mixed"); clicks in the selection and toggle cells never firerowClick. loadingsetsaria-busyon the<table>, and the empty state stays hidden while loading.overlaycovers only the visible part of the table, and a table with no rows keeps the height of its empty state.- Placeholder rows are
aria-hiddenand as tall as a one-line row. Under reduced motion the refresh bar holds still and the shimmer becomes a still wash. stickyHeader,stickyFooter, ormaxHeightswitches toborder-collapse: separate. The last row has no bottom rule; the rule above atfootstays.
Technologies
- The skeleton variant renders
TxSkeleton. The on-demand style plugin loads its sheet; when importing styles by hand, add@talex-touch/tuffex/skeleton/style.css. - Semantic defaults, filtering, and sorting share the internal
useDataTableDatamodule; the internaluseDataTableLayoutmeasures column widths, fixed-column offsets, the veil's height, and the shimmer bands. - Tag and date filters use
TxDropdownMenu/TxDropdownItem, number and text filters useTxPopover; the teleported panels keep component-owned BEM styling. - Source:
packages/tuffex/packages/components/src/data-table/.
Customization
| CSS variable | Used for |
|---|---|
--tx-data-table-row-hover-bg | Row hover fill. |
--tx-data-table-row-selected-bg | Selected-row fill under highlightSelected. |
.records-shell {
--tx-data-table-row-hover-bg: var(--tx-bui-hover);
--tx-data-table-row-selected-bg: color-mix(in srgb, var(--tx-bui-accent) 7%, var(--tx-bui-surface));
}