Skip to content

Table

Table is a data-bound table component rendered as an HTML <table> element. It composes a header, a virtual-scrolling body, and an optional footer, all wired to an AbstractStore.

When no ColumnSpec is supplied, the table auto-generates one column per model field with default sizing.

Quickest example

typescript
import { Model, MemoryStore } from '@jimka/typescript-ui/data';
import { Table } from '@jimka/typescript-ui/component/table';
const PersonModel = new Model([
    { name: 'id',   type: 'number' },
    { name: 'name', type: 'string' },
    { name: 'age',  type: 'number' },
]);

const store = new MemoryStore(PersonModel, [
    { id: 1, name: 'Alice', age: 30 },
    { id: 2, name: 'Bob',   age: 25 },
]);
await store.load();

const table = Table(store);
panel.addComponent(table);

Constraining columns

Pass a ColumnSpec to control which columns appear, their widths, and visibility:

typescript
import { Table } from '@jimka/typescript-ui/component/table';
const table = Table(store, {
    columns: [
        { field: 'name', minWidth: 120 },
        { field: 'age',  maxWidth: 80, hidden: true },
    ],
    appendUnlisted: false,  // skip auto-generated columns for fields not listed
});
ColumnConfig fieldPurpose
fieldModel field name presented in this column.
minWidth / maxWidthWidth constraints in pixels.
hiddenInitial hidden state.
showSecondsFor time / datetime columns: include seconds.

appendUnlisted (default true) controls whether fields not in the columns array are auto-generated after the listed ones.

Sorting and selection

  • Click a column header to cycle through sort directions: ascending → descending → no sort.
  • Shift-click a column header to compose a multi-column sort: each shift-click appends or toggles that column inside the current sort list (asc → desc → removed). When more than one column is active, a small priority badge (2, 3, …) is shown on each non-primary column header.
  • Drag a column header's right edge to resize.
  • Right-click a column header to toggle column visibility via a context menu.
  • table.getSelectedRecord() / getSelectedRecords() return the user's selection.

Common methods

MethodPurpose
getStore() / setStore(store)Read / replace the bound store.
getSelectedRecord() / getSelectedRecords()Current selection.
setColumnVisible(field, boolean)Show / hide a column.
setColumnWidths(widths[])Set all column widths at once.
setHeaderVisible(boolean) / setBodyVisible(boolean) / setFooterVisible(boolean)Toggle structural sections.
exportCSV(options?) / exportJSON(options?)Trigger a download of the current store view.
setExportMenuEnabled(boolean)Adds "Export as CSV" / "Export as JSON" entries to the column context menu.

Exporting

exportCSV() and exportJSON() serialize the current store view — the same filtered, sorted records the user sees — and trigger a browser download. By default only visible columns are included; pass { includeHidden: true } to include columns hidden by the user or by the spec's hidden flag.

typescript
table.exportCSV();                                  // visible columns → table-export.csv
table.exportJSON({ filename: 'people.json' });      // visible columns, custom filename
table.exportCSV({ includeHidden: true });           // every resolved column

To surface export from the column context menu, opt in:

typescript
table.setExportMenuEnabled(true);

CSV output follows RFC 4180: fields containing ,, ", or \n are wrapped in double quotes and interior quotes are doubled. Null and undefined cell values serialize as the empty string (CSV) or null (JSON).

Date, time, and datetime cells are formatted with the same toLocaleDateString / toLocaleTimeString / toLocaleString options the cell renderers use, so exports match what the user sees — including the showSeconds setting from the column spec.

TablePanel exposes the same three methods (setExportMenuEnabled, exportCSV, exportJSON) as delegates to its inner Table.

Performance

The body uses virtual scrolling: only rows visible in the viewport plus a small buffer are in the DOM at any time. A pool of reusable row components is rebound (not recreated) as the user scrolls. Scrolling itself is JS-owned via a VirtualScrollertranslate3d transform plus two custom Scrollbar overlays — with wheel, touch (fling momentum), and keyboard navigation funnelled through the same setScrollY / setScrollX entry points. See Body for the implementation.

Horizontal scrolling kicks in automatically when the combined column width exceeds the table's width.

For large datasets, AbstractStore automatically offloads sort and filter operations to a Web Worker once the dataset exceeds 1,000 rows.

See also