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.
Row Selection
selectable adds a selection column; v-model:selected-keys syncs the selected rows.
Skeleton Loading
loadingVariant="skeleton" draws placeholder rows while there are none; a refresh of existing rows shows only a bar under the header.
Expandable Rows
expandable adds a leading toggle column; the #expanded slot renders the detail under a row.
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"withskeletonRowsset to the page size; keep the defaultoverlayfor short local waits. - Give fixed columns numeric px
width/minWidth, and 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; controlledfilterremains the parent's state. - 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' | 'overlay' | overlay veils the table with a spinner; skeleton draws placeholder rows, or only a bar when rows exist. |
skeletonRows | number | 5 | Placeholder rows before the first data lands; match the page size so nothing moves. |
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. |
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; receives { column, filterValue, setFilter, clearFilter }. |
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. |
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'. Left offsets already 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. |
format | (value, row, index) => string | Cell formatter. |
headerClass | string | Header class. |
cellClass | string | Cell class. |
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 filtering can be driven by a custom filter slot or controlled state.- 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.- Placeholder rows are
aria-hiddenand as tall as a one-line row; the refresh bar holds still under reduced motion. 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. Filter panels useTxPopover; their teleported content keeps 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));
}