Skip to content

Table ​

te-table renders rows from items using headers, with optional search, pagination and per-column slots. Sorting, row selection, pinned columns and column resizing turn it into a data grid without a second component.

Basic ​

Name Role
AdaEngineer
AlanResearcher
vue
<te-table
  :headers="[{ field: 'name', label: 'Name' }, { field: 'role', label: 'Role' }]"
  :items="[{ name: 'Ada', role: 'Engineer' }, { name: 'Alan', role: 'Researcher' }]"
/>

Styling ​

#Name Role
1AdaEngineer
2AlanResearcher
vue
<te-table
  striped hoverable bordered show-row-num compact header-type="dark"
  :headers="[{ field: 'name', label: 'Name' }, { field: 'role', label: 'Role' }]"
  :items="[{ name: 'Ada', role: 'Engineer' }, { name: 'Alan', role: 'Researcher' }]"
/>

Empty state ​

Name
Nothing to show
vue
<te-table :headers="[{ field: 'name', label: 'Name' }]" :items="[]" no-data-label="Nothing to show" />

TableHeader ​

ts
interface TableHeader {
  field?: string;      // key read from each row
  label?: string;      // column heading
  cellClass?: string;  // extra classes on that column's cells
  sortable?: boolean;  // overrides the table-wide `sortable`
  width?: string;      // any CSS length; required on pinned columns
}

Sorting ​

sortable makes every column sortable; a header's own sortable wins over it, so one column can opt out. Clicking a heading cycles ascending → descending → unsorted, and v-model:sort exposes the state as { field, dir }.

Name Role Score
item 10Engineer8
item 2Researcher91
item 1Designer40
sort: none
vue
<te-table sortable :headers="headers" :items="items" v-model:sort="sort" />

Comparison is type-aware: numbers compare numerically, dates by timestamp, and strings through localeCompare with numeric: true — so item 2 sorts before item 10 instead of after it. Empty cells sort last in both directions.

With backendPagination the table does not sort at all. It only emits update:sort, because the client is holding one page and reordering it would scramble the sequence rather than sort the set. Sort on the server and send the page back.

Selecting rows ​

selectable adds a checkbox column bound to v-model:selected.

Name Role Score
item 10Engineer8
item 2Researcher91
item 1Designer40
selected: none
vue
<te-table selectable row-key="id" :headers="headers" :items="items" v-model:selected="selected" />

rowKey names the field that identifies a row, and selected then holds those keys. Without it the array holds the row objects themselves, which only works while items keeps the same object references — so pass a rowKey whenever the rows come from a server.

The header checkbox acts on the current page only, and shows an indeterminate state when part of the page is selected. Paging never clears what you picked on another page.

Sticky header and pinned columns ​

stickyHeader keeps the heading row visible while the body scrolls, which needs a maxHeight to scroll inside. stickyColumns pins the first N columns; the checkbox and row-number columns are pinned with them.

Name Role Score
item 10Engineer8
item 2Researcher91
item 1Designer40
vue
<te-table sticky-header max-height="14rem" :sticky-columns="1" :headers="headers" :items="items" />

A pinned column must declare a width. Pinning is plain position: sticky, and a sticky cell needs an explicit left offset, which the table sums from the widths in front of it — there is no measuring pass, so an undeclared width falls back to 160px and the columns behind it will sit slightly off.

Resizing and reordering columns ​

resizable puts a drag handle on each heading's trailing edge; reorderable lets a heading be dragged onto another. Both keep their state in v-model:column-widths and v-model:column-order, so persisting a user's layout is a matter of storing those two values.

Name Role Score
item 10Engineer8
item 2Researcher91
item 1Designer40

Drag a heading's right edge to resize it, or drag the heading itself onto another.

vue
<te-table
  resizable
  reorderable
  :headers="headers"
  :items="items"
  v-model:column-widths="widths"
  v-model:column-order="order"
/>

columnOrder is a list of fields. A field the list does not mention keeps its original position at the end, so a saved order from an older release never drops a column that was added since.

Props ​

PropTypeDefaultDescription
itemsobject[]— (required)Rows.
headers`(TableHeaderstring)[]`— (required)
searchstring''Filters rows across every column. Resets to page 1.
itemPerPagenumber-1Rows per page. -1 disables pagination.
backendPaginationbooleanfalseThe server already paginates; use with totalItems.
totalItemsnumber0Row count on the server, for backendPagination.
paginationAlign'left' | 'center' | 'right''right'Where the pager sits.
headerType'normal' | 'light' | 'dark''normal'Header background.
striped hoverable bordered borderless centered compactbooleanfalseVisual variants.
responsivebooleantrueHorizontal scrolling on overflow.
showRowNumbooleanfalseAdds a row-number column.
rowNumLabelstring'#'Header of that column.
hasSubheadingbooleanfalseRenders the subheading slot as a first row.
noDataLabelstring'No Data'Text shown when there are no rows.
loadingbooleanfalseOverlays a spinner.
sortablebooleanfalseMakes every column sortable.
selectablebooleanfalseAdds the checkbox column.
rowKeystring''Field identifying a row, for selected.
stickyHeaderbooleanfalseFreezes the heading row. Needs maxHeight.
stickyColumnsnumber0Pins the first N columns.
maxHeightstring''Any CSS length; makes the body scroll.
resizablebooleanfalseDrag handles on the headings.
reorderablebooleanfalseDrag a heading onto another.
minColumnWidthnumber80Smallest width a resize can reach, in px.
labelSelectAll labelSelectRow labelResizestringEnglishAccessible names.

Models ​

ModelTypeDescription
v-model:sort{ field, dir } | nullCurrent sort. null is unsorted.
v-model:selectedunknown[]Row keys, or rows when there is no rowKey.
v-model:column-widthsRecord<string, string>Field → CSS width.
v-model:column-orderstring[]Fields, in display order.

Each of these works uncontrolled: leave it unbound and the table keeps the state itself.

Events ​

EventPayloadDescription
page-changednumberThe page changed.

Slots ​

SlotPropsDescription
<field>{ value, row, index }Custom cell for that column. index is the row's position in the whole set, not in the page.
sort-icon{ header, dir }Replaces the sort indicator.
no-data—Replaces the empty state.
subheading—Extra row under the header.