In this page
<gui-table />
Usage
Column based
const el = document.createElement('gui-table');
const table = gc.core.Table.create([
[
new Date('2019-01-01T15:15:00Z'),
new Date('2019-01-02T15:15:00Z'),
new Date('2020-01-03T15:15:00Z'),
new Date('2021-01-04T15:15:00Z'),
],
[-2.5, 1.458, 0.009, 5.64],
]);
el.value = table;
el.columns = [{ index: 0, header: 'Date' }, { index: 0, header: 'Value' }];
el.addEventListener('gui-table-click', (ev) => {
window.alert(`Clicked row=${ev.detail.rowIdx},col=${ev.detail.colIdx}`);
});
Row based
const el = document.createElement('gui-table');
const table = gc.core.Table.fromRows([
[new Date('2019-01-01T15:15:00Z'), -2.5],
[new Date('2019-01-02T15:15:00Z'), 1.458],
[new Date('2020-01-03T15:15:00Z'), 0.009],
[new Date('2021-01-04T15:15:00Z'), 5.64],
]);
el.value = table;
el.columns = [{ index: 0, header: 'Date' }, { index: 0, header: 'Value' }];
el.addEventListener('gui-table-click', (ev) => {
window.alert(`Clicked row=${ev.detail.rowIdx},col=${ev.detail.colIdx}`);
});
Object based
const el = document.createElement('gui-table');
const table = gc.core.Table.fromObjects([
{ Date: new Date('2019-01-01T15:15:00Z'), Value: -2.5 },
{ Date: new Date('2019-01-02T15:15:00Z'), Value: 1.458 },
{ Date: new Date('2020-01-03T15:15:00Z'), Value: 0.009 },
{ Date: new Date('2021-01-04T15:15:00Z'), Value: 5.64 },
]);
el.value = table;
el.addEventListener('gui-table-click', (ev) => {
window.alert(`Clicked row=${ev.detail.rowIdx},col=${ev.detail.colIdx}`);
});
Global filtering
The following example shows how to add an input to filter the table:
const el = document.createElement('gui-table');
const table = gc.core.Table.fromRows([
['1984', 'George Orwell', 1949, 328],
['To Kill a Mockingbird', 'Harper Lee', 1960, 281],
['The Great Gatsby', 'F. Scott Fitzgerald', 1925, 180],
['One Hundred Years of Solitude', 'Gabriel Garcia Marquez', 1967, 417],
['Moby Dick', 'Herman Melville', 1851, 635],
['War and Peace', 'Leo Tolstoy', 1869, 1225],
['Pride and Prejudice', 'Jane Austen', 1813, 279],
['The Catcher in the Rye', 'J.D. Salinger', 1951, 214],
['The Hobbit', 'J.R.R. Tolkien', 1937, 310],
]);
table.headers = ['Title', 'Author', 'Year Published', 'Pages'];
el.value = table;
el.globalFilter = true;
el.addEventListener('gui-table-click', (ev) => {
window.alert(`Clicked row=${ev.detail.rowIdx},col=${ev.detail.colIdx}`);
});
Sort by column
Table can specify the current column used for sorting by using the sortBy
property.
const el = document.createElement('gui-table');
const table = gc.core.Table.fromRows([
['1984', 'George Orwell', 1949, 328],
['To Kill a Mockingbird', 'Harper Lee', 1960, 281],
['The Great Gatsby', 'F. Scott Fitzgerald', 1925, 180],
['One Hundred Years of Solitude', 'Gabriel Garcia Marquez', 1967, 417],
['Moby Dick', 'Herman Melville', 1851, 635],
['War and Peace', 'Leo Tolstoy', 1869, 1225],
['Pride and Prejudice', 'Jane Austen', 1813, 279],
['The Catcher in the Rye', 'J.D. Salinger', 1951, 214],
['The Hobbit', 'J.R.R. Tolkien', 1937, 310],
]);
table.headers = ['Title', 'Author', 'Year Published', 'Pages'];
el.value = table;
el.sortBy = [2, 'desc']; // 'asc', 'desc' or undefined for default order
Filter by column
Table can be filtered by column using the filterColumns
property.
const el = document.createElement('gui-table');
const table = gc.core.Table.fromRows([
['1984', 'George Orwell', 1949, 328],
['To Kill a Mockingbird', 'Harper Lee', 1960, 281],
['The Great Gatsby', 'F. Scott Fitzgerald', 1925, 180],
['One Hundred Years of Solitude', 'Gabriel Garcia Marquez', 1967, 417],
['Moby Dick', 'Herman Melville', 1851, 635],
['War and Peace', 'Leo Tolstoy', 1869, 1225],
['Pride and Prejudice', 'Jane Austen', 1813, 279],
['The Catcher in the Rye', 'J.D. Salinger', 1951, 214],
['The Hobbit', 'J.R.R. Tolkien', 1937, 310],
]);
table.headers = ['Title', 'Author', 'Year Published', 'Pages'];
el.value = table;
el.filterColumns = ['the'];
Columns
By default, gui-table
automatically displays all columns from the provided table using gui-value
.
If you want finer control over which columns are shown or change their display order, you can set the columns
property.
The order of items in the columns
array determines the display order in the table.
Each column definition must at least specify the target table column via its index
:
const tableEl = document.createElement('gui-table');
tableEl.value = myTable;
tableEl.columns = [
{ index: 4 }, // display myTable[4] as column 0
{ index: 2 }, // display myTable[2] as column 1
];
In this example:
- Table column 4 is displayed first.
- Table column 2 is displayed second.
- All other columns are hidden.
Using Default Columns
If you only want to override or hide specific columns without redefining all of them,
you can enable useDefaultColumns = true
together with the columns
property.
When useDefaultColumns
is true
:
- The table preserves its natural column order.
- Column definitions in
columns
are applied as overrides, not as a new order.
To hide a column in this mode, add hide: true
for that column index:
tableEl.useDefaultColumns = true;
tableEl.columns = [
{ index: 2, hide: true }, // hides column 2
{ index: 4, /* override properties here if needed */ },
];
Cell
By default, gui-table
uses gui-value
to render its cells.
However, you can customize how cells are displayed for each column by overriding the cell
property in the column definition.
The cell
property accepts either:
- A WebComponent tag name, or
- A function used as a render callback.
If using a WebComponent tag, it must implement the
AnyValueElement
interface:
interface AnyValueElement<T> {
get value(): T;
set value(value: T);
}
gui-table
will automatically setcell.value = ...
with the actual cell value on each render.
Tag
In this example, the cell
property is set to 'arrow-icon'
, a custom WebComponent that renders an arrow depending on the sentiment value:
const el = document.createElement('gui-table');
el.value = gc.core.Table.fromObjects([
{ date: new Date('2019-01-01T15:15:00Z'), value: -2.5, sentiment: null },
{ date: new Date('2019-01-02T15:15:00Z'), value: 1.458, sentiment: 'up' },
{ date: new Date('2020-01-03T15:15:00Z'), value: 0.009, sentiment: 'down' },
{ date: new Date('2021-01-04T15:15:00Z'), value: 5.64, sentiment: 'up' },
]);
el.useDefaultColumns = true;
el.columns = [{ index: 2, cell: 'arrow-icon' }];
class ArrowIcon extends HTMLElement {
/** This will be called by `gui-table` to render the cell of column 2 */
set value(value) {
switch (value) {
case 'up':
this.title = value;
this.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none"><path d="M12 6V18M12 6L7 11M12 6L17 11" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
break;
case 'down':
this.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none"><path d="M12 6V18M12 18L7 13M12 18L17 13" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
this.title = value;
break;
default:
this.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none"><path d="M12 19H12.01M8.21704 7.69689C8.75753 6.12753 10.2471 5 12 5C14.2091 5 16 6.79086 16 9C16 10.6565 14.9931 12.0778 13.558 12.6852C12.8172 12.9988 12.4468 13.1556 12.3172 13.2767C12.1629 13.4209 12.1336 13.4651 12.061 13.6634C12 13.8299 12 14.0866 12 14.6L12 16" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
this.title = 'unknown';
}
}
}
if (!customElements.get('arrow-icon')) {
customElements.define('arrow-icon', ArrowIcon);
}
Function
If creating a WebComponent feels like overkill, you can also provide a function directly as cell
.
This function is used as the render callback of a dynamically created element:
const el = document.createElement('gui-table');
el.value = gc.core.Table.fromObjects([
{ date: new Date('2019-01-01T15:15:00Z'), value: -2.5, sentiment: null },
{ date: new Date('2019-01-02T15:15:00Z'), value: 1.458, sentiment: 'up' },
{ date: new Date('2020-01-03T15:15:00Z'), value: 0.009, sentiment: 'down' },
{ date: new Date('2021-01-04T15:15:00Z'), value: 5.64, sentiment: 'up' },
]);
el.useDefaultColumns = true;
el.columns = [{
index: 2,
cell: ({ value }) => {
const el = document.createElement('div');
switch (value) {
case 'up':
el.title = value;
el.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none"><path d="M12 6V18M12 6L7 11M12 6L17 11" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
break;
case 'down':
el.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none"><path d="M12 6V18M12 18L7 13M12 18L17 13" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
el.title = value;
break;
default:
el.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none"><path d="M12 19H12.01M8.21704 7.69689C8.75753 6.12753 10.2471 5 12 5C14.2091 5 16 6.79086 16 9C16 10.6565 14.9931 12.0778 13.558 12.6852C12.8172 12.9988 12.4468 13.1556 12.3172 13.2767C12.1629 13.4209 12.1336 13.4651 12.061 13.6634C12 13.8299 12 14.0866 12 14.6L12 16" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
el.title = 'unknown';
break;
}
return el;
},
}];
Value
For simpler overrides, gui-table
also provides the columns[index].value
hook.
This hook receives the raw cell value and can return anything.
The returned value will then be passed to the underlying cell renderer (e.g. gui-value
):
const el = document.createElement('gui-table');
el.value = gc.core.Table.fromObjects([
{ date: new Date('2019-01-01T15:15:00Z'), value: -2.5, sentiment: null },
{ date: new Date('2019-01-02T15:15:00Z'), value: 1.458, sentiment: 'up' },
{ date: new Date('2020-01-03T15:15:00Z'), value: 0.009, sentiment: 'down' },
{ date: new Date('2021-01-04T15:15:00Z'), value: 5.64, sentiment: 'up' },
]);
el.useDefaultColumns = true;
el.columns = [{
index: 2,
value: ({ value }) => {
switch (value) {
case 'up': return '↑';
case 'down': return '↓';
default: return 'N/A';
}
},
}];
Table Mappings
The mappings utility allows you to create a new table based on an existing table. The new table will have the same rows as the original table, but the columns will be mapped to new columns. This is useful when you want to create a new table with a subset of the columns of the original table.
In the example below, the original table has 3 columns where the 3rd one is an object, so we extract the values from that object into 2 new columns.
The mappings work with any
Object
,Map
,Array
andnode
.
const raw = document.createElement('gui-table');
raw.value = await gc.project.tableMappingExample();
const mapped = document.createElement('gui-table');
// Create the mappings to extract `container.inner.value_a` and `container.inner.value_b`
const mappings = [
new gc.core.TableColumnMapping(gc.project.Container.$fields.inner, ['value_a']),
new gc.core.TableColumnMapping(gc.project.Container.$fields.inner, ['value_b']),
];
mapped.value = await gc.core.Table.applyMappings(raw.table, mappings);
mapped.useDefaultColumns = true;
mapped.columns = [
{ index: gc.project.Container.$fields.inner, hide: true }, // hide the original column
{ index: gc.project.Container.$fields.inner + gc.project.Inner.$fields.value_a + 1, header: 'Value A' },
{ index: gc.project.Container.$fields.inner + gc.project.Inner.$fields.value_b + 1, header: 'Value B' },
];
const el = document.createElement('div');
el.className = 'gui-row';
el.style.gap = '20px';
el.appendChild(raw);
el.appendChild(mapped);
type Container {
name: String;
time: time;
inner: Inner;
}
type Inner {
value_a: int;
value_b: int;
}
@expose
fn tableMappingExample(): Array<Container> {
var arr = Array<Container> {};
var now = time::now();
for (var i = 0; i < 5; i++) {
var container = Container {
name: "container-${i}",
time: now,
inner: Inner {
value_a: i * 2,
value_b: i * 3,
},
};
arr.add(container);
now = now + 1min;
}
return arr;
}
Custom styles
const el = document.createElement('gui-table');
el.classList.add('gui-theme-light', 'custom-style');
el.value = [
{ ident: '189927-1', type: 'MTS', voltage: 20 },
{ ident: '142686-1', type: 'MTS', voltage: 15 },
{ ident: '192771-1', type: 'BTS', voltage: 7 },
];
el.rowHeight = 40;
el.columns = [
{ index: 0 },
{ index: 1 },
{
index: 2,
value: ({ value }) => `${value} kV (MV)`,
},
{
index: 0,
header: '',
filterable: false,
sortable: false,
cell: ({ value }) => {
return gc.web.createElement('sl-icon-button', {
name: 'eye',
label: 'Details',
onclick: () => window.alert(`Clicked: ${value}`),
});
}
}
];
gui-table.custom-style {
--table-head-height: 40px;
--table-border-color: transparent;
}
gui-table.custom-style::part(title) {
font-weight: bold;
}
CSS Variables
Variable | Purpose | Default Value |
---|---|---|
--icon-sort-default |
Icon displayed when column is not sorted | unset |
--icon-sort-asc |
Icon for ascending sort state | ↓ |
--icon-sort-desc |
Icon for descending sort state | ↑ |
--table-spacing |
General spacing/padding throughout table | var(--spacing) |
--table-bg-color |
Main table background color | var(--bg-1) |
--table-cell-bg-color |
Background color for table cells | var(--base-1) |
--table-border-color |
Color for table borders and dividers | var(--border-color) |
--table-filter-border-top-left-radius |
Top-left border radius for filter input | var(--border-radius) |
--table-filter-border-top-right-radius |
Top-right border radius for filter input | var(--border-radius) |
--table-subheader-color |
Color for column subheader text | var(--text-muted) |
--table-resizer-width |
Width of column resize handles | 3px |
--table-resizer-bg-color |
Background color of resize handles | var(--primary) |
--table-resizer-bg-color-hover |
Resize handle color on hover | var(--primary-hover) |
--table-head-height |
Height of table header row | fit-content |
--table-head-bg-color |
Background color of header cells | var(--base-0) |
--table-head-bg-color-hover |
Header cell background on hover | var(--bg-1) |
--table-head-border-color |
Border color for header cells | var(--base-2) |
--table-head-sorter-color-hover |
Sort icon color on hover | var(--primary-hover) |
--table-head-color-active |
Text color for active/sorted columns | var(--accent-0) |
--table-head-filter-bg-color-hover |
Filter button background on hover | var(--primary-focus) |
Slots
Slots | Description |
---|---|
table |
The table container element |
header |
The table header |
header-cell |
For every header cells |
title |
The header cell title |
filter |
The global table input (optional) |
filter-input |
The input of the header cells |
sorter |
The header cell sorting icon |
row |
For every row in the table body |
Events
Name | Detail | Description |
---|---|---|
gui-table-click |
GuiTableEventDetail |
Triggered when a row is clicked |
gui-table-dblclick |
GuiTableEventDetail |
Triggered when a row is double-clicked |
GuiTableEventDetail
export type GuiTableEventDetail = {
/** The clicked row index. */
rowIdx: number;
/** The clicked column index. */
colIdx: number;
};