Table
Table presents structured data for viewing, sorting, selection, and interaction.
Key features:
- Data integration: Load data from APIs via DataSource or use static arrays
- Virtualization: Only renders visible rows for smooth performance with large datasets
- Row selection: Support single or multi-row selection for bulk operations
- Pagination: Built-in pagination controls for managing large datasets
- Inferred columns: Display object arrays even when no
Columnchildren are provided
Use Column to define headers, data binding, sorting behavior, display types, and custom cell content.
If you omit Column children, Table inspects the data records and creates inferred columns automatically.
Explicit Column children always win over inferred columns.
Inferred columns use idKey to identify the row identifier column, so the default idKey="id" infers an id display type for an id field.
UUID-shaped string values infer the more specific uuid display type.
Row identity: The Table uses the id field of each data item as a unique row identifier. This identifier is used for row selection, selectId(), getSelectedIds(), and syncWithVar. If your data uses a different field as the key, set the idKey property to that field name.
Table keeps a bounded cache of recently rendered virtualized rows by default. This reduces remount and measurement flash when users scroll back through content they have already seen. Set renderCache="{false}" to minimize mounted DOM nodes, tune renderCacheSize for the number of recently rendered rows to retain, and use virtualBufferSize when fast scrolling should prepare more never-seen rows just outside the viewport.
In the following sections the examples use data with the structure outlined below:
| Id | Name | Quantity | Unit | Category |
|---|---|---|---|---|
| 0 | Apples | 5 | pieces | fruits |
| 1 | Bananas | 6 | pieces | fruits |
| 2 | Carrots | 100 | grams | vegetables |
| 3 | Spinach | 1 | bunch | vegetables |
| 4 | Milk | 10 | liter | diary |
| 5 | Cheese | 200 | grams | diary |
The data is provided as JSON. In the source code samples, the data={[...]} declaration represents the data above.
All samples use table columns with the following definition unless noted otherwise
(The ... declaration nested into <Table> represents this column definition):
<Table data='{[...]}'>
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>Note: See
Columnto learn more about table columns.
The simplest table can render directly from structured data:
When you provide explicit columns, the table renders only those columns:
Inferred columns with bound fields are sortable by default:
Context variables available during execution:
$cell: The value of the current cell for this column.$colIndex: Zero-based index of the current column.$isExpanded: Whether the current row detail is expanded.$item: The complete data row object being rendered.$itemIndex: Zero-based index of the row in the data array.$row: The complete data row object being rendered (alias of$item).$rowId: The table row ID, derived fromidKeyor the row index.$rowIndex: Zero-based row index (alias of$itemIndex).
Behaviors
This component supports the following behaviors:
| Behavior | Properties |
|---|---|
| Animation | animation, animationOptions |
| Bookmark | bookmark, bookmarkLevel, bookmarkTitle, bookmarkOmitFromToc |
| Component Label | label, labelPosition, labelWidth, labelBreak, required, enabled, shrinkToLabel, style, readOnly |
| Tooltip | tooltip, tooltipMarkdown, tooltipOptions |
| Styling Variant | variant |
Properties
alwaysShowHeader
default: false
This property indicates whether the table header is always visible when scrolling and no height is specified. When set to true, the header is sticky and always visible on page scroll. Otherwise, it scrolls with the content and may not be visible when scrolled down.
alwaysShowPagination
This property explicitly toggles pagination controls visibility. If set to true, controls are always shown even if there is only one page. If set to false, controls are hidden. If omitted, controls are hidden when there is only one page and shown otherwise. This property only has effect when pagination is enabled. It acts as an alias for showPaginationControls.
alwaysShowSelectionCheckboxes
default: false
When set to true, selection checkboxes are always visible for all rows instead of appearing only on hover. Has no effect when hideSelectionCheckboxes is true or when row selection is disabled.
alwaysShowSelectionCheckboxesHeader
default: false
This property indicates when the row selection header is displayed. When the value is true, the selection header is always visible. Otherwise, it is displayed only when hovered.
alwaysShowSortingIndicator
default: false
This property indicates whether the sorting indicator is always visible in the column headers. When set to true, the sorting indicator is always visible. Otherwise, it is visible only when the user hovers over/focuses the column header or the column is sorted.
autoFocus
default: false
If this property is set to true, the component gets the focus automatically when displayed.
buttonRowPosition
default: "center"
Determines where to place the pagination button row in the layout. It works the same as the Pagination component property.
Available values: start, center (default), end
canResizeColumns
default: true
Indicates whether columns can be resized by dragging their header borders. Individual Column components can override this table-level default with their own canResize property.
Set canResizeColumns to false to prevent users from resizing all table columns by default.
The default is true.
Individual Column components can override this table-level default with their own canResize property.
cellUserSelect
default: "none"
This property controls whether users can select text within table cells.
Available values:
| Value | Description |
|---|---|
auto | Default text selection behavior |
text | Text can be selected by the user |
none | Text cannot be selected (default) |
contain | Selection is contained within this element |
all | The entire element content is selected as one unit |
cellVerticalAlign
default: "center"
This property controls the vertical alignment of cell content. It can be set to top, center, or bottom.
Available values: top, center (default), bottom
checkboxTolerance
default: "compact"
This property controls the tolerance area around checkboxes for easier interaction. This property only has an effect when the rowsSelectable property is set to true. none provides no tolerance (0px), compact provides minimal tolerance (8px), comfortable provides medium tolerance (12px), and spacious provides generous tolerance (16px) for improved accessibility.
Available values: none, compact (default), comfortable, spacious
The default value is false.
<App>
<Table data='{[...]}'
rowsSelectable="true"
checkboxTolerance="comfortable"
>
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>columnInference
default: "first-n(25)"
Controls how the Table samples the resolved data array when it has no explicit Column children and needs to infer columns and display types. The default is first-n(25). Use first-only for the fastest inference, first-n(n) for a bounded prefix, sample(n) for deterministic spread sampling, all for small datasets, or off to disable inferred columns. This setting inspects row objects only; unwrap API response envelopes before passing data to the table.
columnInference controls how Table samples data when no Column children are provided.
The default is first-n(25), which inspects the first 25 records and infers both field names and display types from those sampled values.
Useful values:
first-only: infer from the first row onlyfirst-n(25): infer from the first 25 rows; this is the defaultsample(25): infer from a deterministic spread of rowsall: inspect every row; use this only for small datasetsoff: do not infer columns
The 25 in first-n(25) and sample(25) is only an example.
Use any positive integer that fits the data size and cost you want, such as first-n(5), first-n(100), or sample(50).
columnInference expects the table's data value to be the row array itself.
If an API returns an envelope such as { items: [...] }, unwrap that envelope before passing the value to Table.
How Inference Works
Column inference runs only when the Table has no explicit Column children.
If you add any Column children, those columns define the table instead of the inferred columns.
The table expects data to resolve to an array of row objects.
Only plain object rows participate in field discovery; primitive values, arrays, dates, inherited properties, and non-enumerable properties are ignored.
The internal order field is also skipped.
| Step | Rule |
|---|---|
| 1. Sample rows | first-only, first-n(n), sample(n), all, or off decides which rows are inspected. sample(n) uses a deterministic spread across the supplied array. |
| 2. Discover fields | The table reads enumerable own keys from sampled row objects. Field order follows first discovery: keys from earlier sampled rows come first, and newly discovered keys from later sampled rows are appended. |
| 3. Create columns | Each discovered field becomes a sortable inferred column with header and accessorKey set to the field name. |
| 4. Infer type | The sampled values for each field are inspected and mapped to a Column type. |
| 5. Apply layout | The inferred type participates in columnSizing; numeric-like types align to the end, compact types get compact default widths in balanced sizing, and text-like types can use star sizing. |
Type inference ignores null, undefined, and empty string values when deciding the type.
If no present values remain, or if the sampled values are mixed in a way the table cannot classify, the type falls back to text.
| Sampled values | Inferred type |
|---|---|
| UUID-shaped strings | uuid |
Scalar values in the field named by idKey | id |
| Finite numbers | integer when all numbers are integers; otherwise number |
| Booleans | boolean |
| Arrays of short strings | tags |
| Other arrays | array |
| Plain objects | object |
| ISO date strings | date |
| ISO datetime strings | datetime |
| Mostly email, URL, or phone strings | email, url, or phone |
Name-like fields such as name, customer, customerName, displayName, fullName, or fields ending in Name | name |
| Any string longer than 80 characters | long-text |
| Low-cardinality short string sets | enum |
| Other strings or unknown mixed values | text |
Inference is display-oriented.
It does not validate data, mutate rows, unwrap API response envelopes, or inspect server-side pages that are not present in the supplied data array.
Use explicit Column children when you need guaranteed columns, labels, ordering, types, sizing, or custom cell content.
<App>
<Table
columnInference="first-only"
data='{[
{ id: 1, customer: "Ada" },
{ id: 2, customer: "Grace", total: 87.5 }
]}'
/>
</App><App>
<Table
columnInference="first-only"
data='{[
{ id: 1, customer: "Ada" },
{ id: 2, customer: "Grace", total: 87.5 }
]}'
/>
</App>Use first-n(n) when the first record may be sparse, but the useful fields appear near the beginning of the data:
<App>
<Table
columnInference="first-n(3)"
data='{[
{ id: 1, customer: "Ada" },
{ id: 2, customer: "Grace", total: 87.5 },
{ id: 3, customer: "Linus", paid: true },
{ id: 4, customer: "Margaret", internalNote: "Not sampled" }
]}'
/>
</App><App>
<Table
columnInference="first-n(3)"
data='{[
{ id: 1, customer: "Ada" },
{ id: 2, customer: "Grace", total: 87.5 },
{ id: 3, customer: "Linus", paid: true },
{ id: 4, customer: "Margaret", internalNote: "Not sampled" }
]}'
/>
</App>Use sample(n) when fields may appear later in a larger local array and you want a deterministic spread instead of only the first records:
<App>
<Table
columnInference="sample(3)"
data='{[
{ id: 1, customer: "Ada" },
{ id: 2, customer: "Grace" },
{ id: 3, customer: "Linus", total: 87.5 },
{ id: 4, customer: "Margaret" },
{ id: 5, customer: "Katherine", status: "paid" }
]}'
/>
</App><App>
<Table
columnInference="sample(3)"
data='{[
{ id: 1, customer: "Ada" },
{ id: 2, customer: "Grace" },
{ id: 3, customer: "Linus", total: 87.5 },
{ id: 4, customer: "Margaret" },
{ id: 5, customer: "Katherine", status: "paid" }
]}'
/>
</App>idKey also guides inferred display types.
The field named by idKey is inferred as id; UUID-shaped string values are inferred as uuid.
<App>
<Table
idKey="customerId"
data='{[
{
customerId: "C-001",
name: "Ada",
traceId: "47f4d9f8-2f6a-4e3d-9bf5-010d74822c6f"
},
{
customerId: "C-002",
name: "Grace",
traceId: "550e8400-e29b-41d4-a716-446655440000"
}
]}'
/>
</App><App>
<Table
idKey="customerId"
data='{[
{
customerId: "C-001",
name: "Ada",
traceId: "47f4d9f8-2f6a-4e3d-9bf5-010d74822c6f"
},
{
customerId: "C-002",
name: "Grace",
traceId: "550e8400-e29b-41d4-a716-446655440000"
}
]}'
/>
</App>columnSizing
default: "auto"
Controls how automatically sized columns consume horizontal space. stretch keeps the traditional equal-fill behavior, balanced uses type-aware defaults so compact types such as IDs and numbers stay narrow while text-like columns use star sizing, content prefers compact fixed widths, and auto uses balanced for inferred columns while preserving stretch for explicit columns.
Available values: auto (default), stretch, balanced, content
columnSizing controls how automatically sized columns consume horizontal space.
Available values:
auto: use type-aware balanced sizing for inferred columns, and preserve the traditional stretch behavior for explicit columnsstretch: distribute available width among columns that do not specifywidthbalanced: keep compact types such asid, numbers, booleans, and dates narrow, while text-like types use star sizingcontent: prefer compact fixed widths for typed columns
Explicit Column values such as width, minWidth, maxWidth, and horizontalAlignment override type-aware defaults.
<App>
<Table
columnSizing="balanced"
data='{[
{ id: 1, customer: "Ada", total: 123.45 },
{ id: 2, customer: "Grace", total: 87.5 }
]}'
/>
</App><App>
<Table
columnSizing="balanced"
data='{[
{ id: 1, customer: "Ada", total: 123.45 },
{ id: 2, customer: "Grace", total: 87.5 }
]}'
/>
</App>data
The component receives data via this property. The data property is a list of items that the Table can display.
<App>
<Table data='{[...]}'>
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>You can also provide the Table with data directly from an API via this property.
Here, the component displays rocket information coming from the official SpaceX API.
<App>
<Table data='https://api.spacexdata.com/v3/rockets'>
<Column header="Image" size="140px">
<Image height="100px" fit="cover" src="{$item.flickr_images[0]}"/>
</Column>
<Column canSort="true" bindTo="country"/>
<Column canSort="true" bindTo="company"/>
</Table>
</App><App>
<Table data='https://api.spacexdata.com/v3/rockets'>
<Column header="Image" size="140px">
<Image height="100px" fit="cover" src="{$item.flickr_images[0]}"/>
</Column>
<Column canSort="true" bindTo="country"/>
<Column canSort="true" bindTo="company"/>
</Table>
</App>dataRefreshMode
default: "reset"
Controls how the table handles later data refreshes after the initial load. reset keeps the table's default refresh behavior. preserve-state reconciles refreshed data with the current view state for unchanged source row IDs.
Available values: reset (default), preserve-state
Use dataRefreshMode="preserve-state" when a Table receives refreshed data after backend mutations. The table keeps the current scroll position, sort state, pagination state when still valid, column sizing, and row selection for source rows whose idKey values still exist. If deletion leaves the current page beyond the new page count, the table clamps to the last available page.
For a complete backend-style insert, update, and delete workflow, see Preserve collection state across data refreshes.
For mutation flows where only the next refresh should preserve state, call preserveStateOnNextDataRefresh() before updating or refetching the data:
Stable, unique idKey values are required. If an inserted row is outside the current viewport and is present in the current row model, operation: "insert" or scrollTarget: "first-inserted" scrolls it into view after reconciliation. For paginated tables, insert targeting does not switch pages.
defaultSortDirection
default: "ascending"
Sets which direction the first click on a column header sorts. Use descending for tables whose interesting rows are the largest ones (counts, totals, percentages), so one click gives the useful order instead of two. The click cycle keeps three states and only its starting point moves: with descending it runs descending, ascending, unsorted. Individual Column components override this with their own defaultSortDirection. It also supplies the initial direction when sortBy is set without an explicit sortDirection, so a table declared biggest-first opens that way rather than needing a click.
Available values: ascending (default), descending
Some columns are only interesting from the top: vote counts, totals, percentages.
A header click sorts ascending first, so those columns cost an extra click before
they show anything useful. defaultSortDirection moves where the click cycle
starts.
The problem
No configuration here. Click Votes once and you get the smallest count first; click again for the largest.
<Table data='{[...]}'>
<Column bindTo="candidate"/>
<Column bindTo="votes" canSort="true"/>
</Table>Two clicks to answer "who won". On one table that is a shrug; across a screenful of count columns it is the difference between a table you read and a table you operate.
One line fixes the click count
<Table data='{[...]}' defaultSortDirection="descending">
<Column bindTo="candidate"/>
<Column bindTo="votes" canSort="true"/>
</Table>Click Votes once: biggest first. The cycle still has three states and still ends unsorted — descending, ascending, unsorted. Only its starting point moved.
Opening already sorted
The property above says which direction. It never says which column, so the
table still opens unsorted until you click. To arrive sorted, name the column
with sortBy:
<Table data='{[...]}' sortBy="votes" defaultSortDirection="descending">
<Column bindTo="candidate"/>
<Column bindTo="votes" canSort="true"/>
</Table>Zero clicks: biggest first on load. defaultSortDirection supplies the opening
direction because no explicit sortDirection was given — set
that instead when the opening order should differ from what clicking produces.
A seeded table is already at the first stage of the cycle, so the first click advances to the second stage rather than confirming the first. Clicking Votes here goes to ascending, then to unsorted. That is worth knowing before it surprises you: on a seeded column, the first click looks like it reverses the sort.
One column that reads the other way
Names are the case where alphabetical is the natural first read, even in a table
of counts. A Column overrides its table:
<Table data='{[...]}' defaultSortDirection="descending">
<Column bindTo="candidate" canSort="true" defaultSortDirection="ascending"/>
<Column bindTo="votes" canSort="true"/>
</Table>Neither column is sorted on load — there is no sortBy here. Click Votes and
it goes largest-first; click Candidate and it goes A–Z. Resolution is column
first, then table, then ascending.
Switching columns restarts the cycle at the new column's own first direction; it does not carry the previous column's stage across. Clicking Votes then Candidate gives descending then ascending, each column's own default.
enableMultiRowSelection
default: true
This boolean property indicates whether you can select multiple rows in the table. This property only has an effect when the rowsSelectable property is set. Setting it to false limits selection to a single row.
This boolean property indicates whether you can select multiple rows in the table.
This property only has an effect when the rowsSelectable property is set.
Setting it to false limits selection to a single row.
By default, the value of this property is true.
<App>
<Table data='{[...]}'
rowsSelectable="true"
enableMultiRowSelection="false">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>expandedRowIds
Controlled list of expanded row IDs. Pair this with rowExpansionDidChange to own row expansion state outside the table.
headerHeight
This optional property is used to specify the height of the table header.
It accepts common size values.
<App>
<Table data='{[...]}' headerHeight="60px">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>headerUserSelect
default: "text"
This property controls whether users can select text within table headers.
Available values:
| Value | Description |
|---|---|
auto | Default text selection behavior |
text | Text can be selected by the user (default) |
none | Text cannot be selected |
contain | Selection is contained within this element |
all | The entire element content is selected as one unit |
hideHeader
default: false
Set the header visibility using this property. Set it to true to hide the header.
Set the header visibility using this property. Set it to true to hide the header.
The default value is false.
<App>
<Table data='{[...]}' hideHeader="true">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>hideSelectionCheckboxes
default: false
If true, hides selection checkboxes for both rows and header. Selection logic still works via API and keyboard.
Hides the selection checkboxes in both the header and rows while keeping the selection API and keyboard selection behavior intact. Useful when you want selection functionality without visible checkboxes.
The default value is false.
<App>
<Table data='{[...]}' rowsSelectable="true" enableMultiRowSelection="true" hideSelectionCheckboxes="true">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>hideSelectionCheckboxesHeader
default: false
If true, the selection checkbox in the table header is never displayed, not even on hover. Row checkboxes are unaffected. Selection logic still works via API and keyboard.
Hides the selection checkbox in the table header so it is never displayed, not even on hover. Row checkboxes are unaffected. Selection logic still works via the component API and keyboard shortcuts.
The default value is false.
<App>
<Table data='{[...]}' rowsSelectable="true" enableMultiRowSelection="true" hideSelectionCheckboxesHeader="true">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>highlightHoveredColumn
default: false
When set to true, hovering a table cell tints its entire column with the backgroundColor-column-Table--hover theme variable. The default is false: no cell hover handlers are attached and the rendered output is unchanged. Where the hovered row and the hovered column intersect, the row highlight wins. Pinned columns keep their own hover background instead of the column tint.
Column headers already highlight on hover, but by default hovering a cell in the table body only highlights its row — nothing marks which column you are in. On a wide table this makes it easy to lose track of which field you are reading as your eye travels down a column.
Set highlightHoveredColumn to true to tint the entire hovered column with the backgroundColor-column-Table--hover theme variable. The default is false: no cell hover handlers are attached and the table renders exactly as it does today.
Where the hovered row and the hovered column intersect, the row highlight wins — the column tint never competes with or muddies the row's own hover color. Pinned columns keep their existing hover background instead of showing the column tint, since the pointer being elsewhere in the table should not change how a pinned column looks.
<App>
<Table data='{[...]}' highlightHoveredColumn="true">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>Hover any cell to see its whole column tinted, and hover a row to see the row highlight take precedence where the two overlap:
iconNoSort
Allows setting an alternate icon displayed in the Table column header when sorting is enabled, but the column remains unsorted. You can change the default icon for all Table instances with the "icon.nosort:Table" declaration in the app configuration file.
Allows the customization of the icon displayed in a Table column header when when sorting is enabled and sorting is not done according to the column. Use the "-" (dash) value to sign that you do not want to display an icon when a table column is not sorted.
<App>
<Table data='{[...]}' sortBy="quantity" iconNoSort="close">
<Column bindTo="name" canSort="true" />
<Column bindTo="quantity" canSort="true" />
<Column bindTo="unit" canSort="true" />
</Table>
</App>iconSortAsc
Allows setting an alernate icon displayed in the Table column header when sorting is enabled, and the column is sorted in ascending order. You can change the default icon for all Table instances with the "icon.sortasc:Table" declaration in the app configuration file.
Allows the customization of the icon displayed in a Table column header when sorting is enabled, sorting is done according to the column, and the column is sorted in ascending order.
<App>
<Table data='{[...]}' sortBy="quantity" iconSortAsc="chevronup">
<Column bindTo="name" canSort="true" />
<Column bindTo="quantity" canSort="true" />
<Column bindTo="unit" canSort="true" />
</Table>
</App>iconSortDesc
Allows setting an alternate icon displayed in the Table column header when sorting is enabled, and the column is sorted in descending order. You can change the default icon for all Table instances with the "icon.sortdesc:Table" declaration in the app configuration file.
Allows the customization of the icon displayed in a Table column header when sorting is enabled, sorting is done according to the column, and the column is sorted in descending order.
<App>
<Table data='{[...]}' sortBy="quantity" iconSortDesc="chevrondown">
<Column bindTo="name" canSort="true" />
<Column bindTo="quantity" canSort="true" />
<Column bindTo="unit" canSort="true" />
</Table>
</App>Select a column header and set it to descending ordering.
idKey
default: "id"
This property is used to specify the unique ID property in the data array. If the idKey points to a property that does not exist in the data items, that will result in incorrect behavior when using selectable rows.
<App>
<Table
idKey="key"
rowsSelectable="true"
data="{[
{ 'key': 0, 'name': 'John' },
{ 'key': 1, 'name': 'Jane' },
{ 'key': 2, 'name': 'Bill' },
]}"
>
<Column bindTo="name"/>
</Table>
</App>initiallyExpandedRowIds
Initial list of expanded row IDs for uncontrolled row details. Later changes to this property do not replace the current expansion state.
initiallySelected
An array of IDs that should be initially selected when the table is rendered. This property only has an effect when the rowsSelectable property is set to true.
isPaginated
default: false
This property adds pagination controls to the Table. When enabled, the pagination bar is automatically hidden if all rows fit on a single page. You can omit this property and set only pageSize instead — pagination will then activate automatically when the data length exceeds the page size and hide itself when it does not.
<App>
<Table data='{[...]}' isPaginated="true" pageSizeOptions="{[3, 6, 12]}">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>keyBindings
This property defines keyboard shortcuts for table actions. Provide an object with action names as keys and keyboard shortcut strings as values. The shortcut strings use Electron accelerator syntax (e.g., 'CmdOrCtrl+A', 'Delete'). Available actions: selectAll, cut, copy, paste, delete. If not provided, default shortcuts are used.
This property uses the following default key bindings:
{
"selectAll": "CmdOrCtrl+A",
"cut": "CmdOrCtrl+X",
"copy": "CmdOrCtrl+C",
"paste": "CmdOrCtrl+V",
"delete": "Delete"
}You can use these accelerator key names:
CmdOrCtrl: Command on macOS, Ctrl on Windows/LinuxAlt: Alt/OptionsShift: ShiftSuper: Command on macOS, Windows key on Windows/LinuxCtrl: Control keyCmd: Command key (macOS only)
loading
This boolean property indicates if the component is fetching (or processing) data. This property is useful when data is loaded conditionally or receiving it takes some time.
This boolean property indicates if the component is fetching (or processing) data.
This property is useful when data is loaded conditionally or receiving it takes some time. While
loading is true and no rows are available, the table shows its loading UI after the configured
loadingDelay.
<App>
<Table loading="true" loadingDelay="0">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
</Table>
</App><App>
<Table loading="true" loadingDelay="0">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
</Table>
</App>loadingDelay
default: 400
The delay in milliseconds before showing the loading UI. Set to 0 to show immediately, or a higher value to prevent flicker for fast-loading data.
The loadingDelay property controls how many milliseconds the table waits before showing its loading
UI. The default is 400, which prevents flicker when data loads quickly. Set it to 0 to show the
loading UI immediately.
<App var.isLoading="{false}" var.items="{[]}">
<Button
label="Load"
onClick="isLoading = true; delay(1000); items = [{ id: 1, name: 'Loaded row', quantity: 1 }]; isLoading = false" />
<Table loading="{isLoading}" loadingDelay="400" data="{items}">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
</Table>
</App><App var.isLoading="{false}" var.items="{[]}">
<Button
label="Load"
onClick="isLoading = true; delay(1000); items = [{ id: 1, name: 'Loaded row', quantity: 1 }]; isLoading = false" />
<Table loading="{isLoading}" loadingDelay="400" data="{items}">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
</Table>
</App>noBottomBorder
default: false
This property indicates whether the table should have a bottom border. When set to true, the table does not have a bottom border. Otherwise, it has a bottom border.
noDataTemplate
A property to customize what to display if the table does not contain any data.
<App>
<Table>
<property name="noDataTemplate">
<Text value="No data loaded" variant="strong" />
</property>
<Column bindTo="name"/>
<Column bindTo="quantity"/>
</Table>
</App><App>
<Table>
<property name="noDataTemplate">
<Text value="No data loaded" variant="strong" />
</property>
<Column bindTo="name"/>
<Column bindTo="quantity"/>
</Table>
</App>pageInfoPosition
default: "end"
Determines where to place the page information in the layout. It works the same as the Pagination component property.
pageSize
This property defines the number of rows to display per page. When set without also setting isPaginated, pagination is activated automatically whenever the number of data rows exceeds this value and suppressed otherwise. This makes pageSize the minimal way to get auto-activating, auto-hiding pagination: no conditional expressions on isPaginated or the position props are needed.
Options
Page sizes are only accepted in an array, even if the array contains one item.
Note that this property only works if the isPaginated property is set to true.
<App>
<Table data='{[...]}' isPaginated="true" pageSizeOptions="{[3, 6, 12]}">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>pageSizeOptions
This property holds an array of page sizes (numbers) the user can select for pagination. If this property is not defined, the component allows only a page size of 10 items.
Page sizes are only accepted in an array, even if the array contains one item.
Note that this property only works if the isPaginated property is set to true.
<App>
<Table data='{[...]}' isPaginated="true" pageSizeOptions="{[3, 6, 12]}">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>pageSizeSelectorPosition
default: "start"
Determines where to place the page size selector in the layout. It works the same as the Pagination component property.
paginationControlsLocation
default: "bottom"
This property determines the location of the pagination controls. It can be set to top, bottom, or both.
Available values: top, bottom (default), both
refreshOn
An expression whose value change forces all table rows and cells to re-render. Use this to ensure that closure variables bound in row or cell templates are updated when global state changes (e.g. {selectMode}). Without this, virtualized rows might retain stale references to global variables for performance reasons.
renderCache
default: true
Controls whether the table keeps a bounded set of recently rendered virtualized rows mounted while they are outside the viewport. Keeping rows mounted reduces remount and measurement flash when users scroll back through recently viewed content.
renderCacheSize
default: 80
Maximum number of recently rendered virtualized rows to keep mounted when renderCache is enabled. Larger values can make repeat scrolling smoother but retain more DOM nodes.
rowDetailTemplate
Template rendered in a full-width detail area beneath an expanded row. When this property is set, the table adds an expansion control column automatically. The template receives $item, $row, $itemIndex, $rowIndex, $rowId, and $isExpanded.
rowDisabledPredicate
This property defines a predicate function with a return value that determines if the row should be disabled. The function retrieves the item to display and should return a Boolean-like value.
The following example disables all table rows where the item's quantity exceeds 6:
<App>
<Table data='{[...]}'
rowDisabledPredicate="{(item) => item.quantity > 6}">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>Disabled items are rendered with a different color.
rowsSelectable
Indicates whether the rows are selectable (true) or not (false).
The default value is false.
<App>
<Table data='{[...]}' rowsSelectable="true">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>rowUnselectablePredicate
This property defines a predicate function with a return value that determines if the row should be unselectable. The function retrieves the item to display and should return a Boolean-like value. This property only has an effect when the rowsSelectable property is set to true.
rowVariant
This property defines a function that names a styling variant for a row. The function receives the row item and returns a variant name (such as "playing" or "warning"), or a falsy value for no variant. A row with variant <name> uses the backgroundColor-row-<name>-Table, backgroundColor-row-<name>-Table--hover and textColor-row-<name>-Table theme variables. A variant background takes precedence over striped rows; selected and hovered rows keep their own background, while the variant's text color still applies. Names must start with a letter and contain only letters, digits, - and _.
The following example tints the rows of low-stock items. The function returns the variant name low for them, and the backgroundColor-row-low-Table and textColor-row-low-Table theme variables style those rows:
<App>
<Theme
backgroundColor-row-low-Table="$color-warn-100"
textColor-row-low-Table="$color-danger-500">
<Table
data="{[
{ id: 1, name: 'Apples', quantity: 5 },
{ id: 2, name: 'Bananas', quantity: 0 },
{ id: 3, name: 'Carrots', quantity: 100 },
{ id: 4, name: 'Spinach', quantity: 1 }
]}"
rowVariant="{(item) => item.quantity < 2 ? 'low' : null}">
<Column bindTo="name" />
<Column bindTo="quantity" />
</Table>
</Theme>
</App><App>
<Theme
backgroundColor-row-low-Table="$color-warn-100"
textColor-row-low-Table="$color-danger-500">
<Table
data="{[
{ id: 1, name: 'Apples', quantity: 5 },
{ id: 2, name: 'Bananas', quantity: 0 },
{ id: 3, name: 'Carrots', quantity: 100 },
{ id: 4, name: 'Spinach', quantity: 1 }
]}"
rowVariant="{(item) => item.quantity < 2 ? 'low' : null}">
<Column bindTo="name" />
<Column bindTo="quantity" />
</Table>
</Theme>
</App>The function can also read app state, for example rowVariant="{(item) => item.id === playingId ? 'playing' : null}", and the rows update when that state changes. Selected and hovered rows keep their own background, while the variant's text color still applies. backgroundColor-row-<name>-Table--hover sets the hover color of a variant row.
See Highlight rows conditionally for more.
showCurrentPage
default: true
Whether to show the current page indicator. It works the same as the Pagination component property.
showPageInfo
default: true
Whether to show page information. It works the same as the Pagination component property.
showPageSizeSelector
default: true
Whether to show the page size selector. It works the same as the Pagination component property.
sortBy
This property is used to determine which data property to sort by. If not defined, the data is not sorted
<App>
<Table data='{[...]}' sortBy="quantity">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>sortDirection
This property determines the sort order to be ascending or descending. This property only works if the sortBy property is also set. By default ascending order is used.
<App>
<Table data='{[...]}' sortBy="quantity" sortDirection="descending">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>striped
default: false
When set to true, the table rows alternate between the backgroundColor-evenRow-Table and backgroundColor-oddRow-Table theme variables, creating a striped appearance.
<App>
<Table data='{[...]}' striped="true">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>syncWithAppState
An AppState instance to synchronize the table's selection state with. The table will read from and write to the 'selectedIds' property of the AppState object. When provided, this takes precedence over the initiallySelected property for initial selection. You can use the AppState's didUpdate event to receive notifications when the selection changes.
syncWithVar
The name of a global variable to synchronize the table's selection state with. The named variable must reference an object; the table will read from and write to its 'selectedIds' property. When provided, this takes precedence over both initiallySelected and syncWithAppState. Multiple tables sharing the same variable name will keep their selections in sync automatically. A runtime error is signalled if the value is not a valid JavaScript variable name.
The following example demonstrates how two independent MyTable components share selection state through a global variable. Selecting a row in either table immediately reflects in the other, and selState always holds the current selection:
syncWithVarworks with both global and local variables. When using local variables, ensure all Tables in the sync have that variable in their scope.
<App global.selState="{{}}">
<MyTable />
<Text>Selection: {JSON.stringify(selState)}</Text>
<MyTable />
</App><Component name="MyTable">
<Table
syncWithVar="selState"
rowsSelectable="true"
data='{[
{ id: 0, name: "Apples", quantity: 5, unit: "pieces" },
{ id: 1, name: "Bananas", quantity: 6 },
{ id: 2, name: "Carrots", quantity: 100, unit: "grams" },
]}'
>
<Column bindTo="name" />
<Column bindTo="quantity" />
<Column bindTo="unit" />
</Table>
</Component>Change the selection in one of the tables and check how it is synced.
<App global.selState="{{}}">
<MyTable />
<Text>Selection: {JSON.stringify(selState)}</Text>
<MyTable />
</App><Component name="MyTable">
<Table
syncWithVar="selState"
rowsSelectable="true"
data='{[
{ id: 0, name: "Apples", quantity: 5, unit: "pieces" },
{ id: 1, name: "Bananas", quantity: 6 },
{ id: 2, name: "Carrots", quantity: 100, unit: "grams" },
]}'
>
<Column bindTo="name" />
<Column bindTo="quantity" />
<Column bindTo="unit" />
</Table>
</Component>Change the selection in one of the tables and check how it is synced.
toggleSelectionOnClick
default: false
When true, a plain click toggles the row's selection state instead of replacing the current selection. Ctrl+Click and Shift+Click behavior is unchanged. Only has an effect when rowsSelectable is true.
When true, a plain click toggles the row's selection state (adds it if not selected, removes it if already selected) instead of replacing the current selection with just that row.
This property only has an effect when rowsSelectable is true. Ctrl+Click and Shift+Click behavior is unchanged.
The default value is false.
<App>
<Table data='{[...]}' rowsSelectable="true" toggleSelectionOnClick="true">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
<Column bindTo="unit"/>
</Table>
</App>userSelectCell
default: "auto"
This property controls whether users can select text within table cells.
Available values:
| Value | Description |
|---|---|
auto | Default text selection behavior (default) |
text | Text can be selected by the user |
none | Text cannot be selected |
contain | Selection is contained within this element |
all | The entire element content is selected as one unit |
userSelectHeading
default: "none"
This property controls whether users can select text within table headings. Use text to allow text selection, none to prevent selection, or auto for default behavior.
Available values:
| Value | Description |
|---|---|
auto | Default text selection behavior |
text | Text can be selected by the user |
none | Text cannot be selected (default) |
contain | Selection is contained within this element |
all | The entire element content is selected as one unit |
userSelectRow
default: "auto"
This property controls whether users can select text within table rows. Use text to allow text selection, none to prevent selection, or auto for default behavior.
Available values:
| Value | Description |
|---|---|
auto | Default text selection behavior (default) |
text | Text can be selected by the user |
none | Text cannot be selected |
contain | Selection is contained within this element |
all | The entire element content is selected as one unit |
virtualBufferSize
Extra virtualizer buffer, in pixels, to render before and after the viewport. Increase this when fast scrolling reaches rows that have not been rendered before; unlike renderCache, this prepares never-seen rows near the viewport.
Events
contextMenu
This event is triggered when the Table is right-clicked (context menu).
Signature: contextMenu(event: MouseEvent): void
event: The mouse event object.
copyAction
This event is triggered when the user presses the copy keyboard shortcut (default: Ctrl+C/Cmd+C) and rowsSelectable is set to true. The handler receives three parameters: the focused row, selected items, and selected IDs. The handler should implement the copy logic (e.g., using the Clipboard API to copy selected data).
Signature: copy(row: TableRowContext | null, selectedItems: any[], selectedIds: string[]): void | Promise<void>
row: The currently focused row context, or null if no row is focused.selectedItems: Array of selected row items.selectedIds: Array of selected row IDs (as strings).
cutAction
This event is triggered when the user presses the cut keyboard shortcut (default: Ctrl+X/Cmd+X) and rowsSelectable is set to true. The handler receives three parameters: the focused row, selected items, and selected IDs. Note: The component does not automatically modify data; the handler must implement the cut logic (e.g., copying data to clipboard and removing from the data source).
Signature: cut(row: TableRowContext | null, selectedItems: any[], selectedIds: string[]): void | Promise<void>
row: The currently focused row context, or null if no row is focused.selectedItems: Array of selected row items.selectedIds: Array of selected row IDs (as strings).
deleteAction
This event is triggered when the user presses the delete keyboard shortcut (default: Delete key) and rowsSelectable is set to true. The handler receives three parameters: the focused row, selected items, and selected IDs. Note: The component does not automatically remove data; the handler must implement the delete logic (e.g., removing selected items from the data source).
Signature: delete(row: TableRowContext | null, selectedItems: any[], selectedIds: string[]): void | Promise<void>
row: The currently focused row context, or null if no row is focused.selectedItems: Array of selected row items.selectedIds: Array of selected row IDs (as strings).
pasteAction
This event is triggered when the user presses the paste keyboard shortcut (default: Ctrl+V/Cmd+V) and rowsSelectable is set to true. The handler receives three parameters: the focused row, selected items, and selected IDs. The handler must implement the paste logic (e.g., reading from clipboard and inserting data into the table).
Signature: paste(row: TableRowContext | null, selectedItems: any[], selectedIds: string[]): void | Promise<void>
row: The currently focused row context, or null if no row is focused.selectedItems: Array of selected row items.selectedIds: Array of selected row IDs (as strings).
rowClick
This event is fired when the user clicks a table row. The handler receives the clicked row item as its only argument. It reports the click without replacing or suppressing selection — pair it with rowsSelectable deliberately, and prefer selectionDidChange when what you actually care about is the selection. The event does not fire for clicks on the selection checkbox or on an interactive control (such as a button) inside a cell.
Signature: rowClick(item: any): void
item: The clicked table row item.
This event is triggered when a table row is clicked. The handler receives the row's data item as its only argument.
rowClick reports activation — it does not replace or suppress selection. Row click already runs a selection toggle when rowsSelectable is set, and rowClick fires alongside that without interfering with it: pair it with rowsSelectable deliberately, and prefer selectionDidChange when what you actually care about is the selection rather than the click itself. rowClick does not fire for a click on the selection checkbox, nor for a click on an interactive control (such as a button) inside a cell.
<App>
<Table data='{[...]}' onRowClick="(item) => console.log(item)">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
</Table>
</App>rowDoubleClick
This event is fired when the user double-clicks a table row. The handler receives the clicked row item as its only argument.
Signature: rowDoubleClick(item: any): void
item: The clicked table row item.
This event is triggered when a table row is double-clicked. The handler receives the row's data item as its only argument.
<App>
<Table data='{[...]}' onRowDoubleClick="(item) => console.log(item)">
<Column bindTo="name"/>
<Column bindTo="quantity"/>
</Table>
</App>rowEnter
This event is fired when the pointer enters a table row. The handler receives the row item as its only argument. Use it with rowLeave to link the table to another view — highlighting the matching point on a chart, or showing the hovered record in a detail panel. Moving between cells of the same row does not re-fire it.
Signature: rowEnter(item: any): void
item: The hovered table row item.
This event fires when the pointer enters a table row. The handler receives the row's data item as its only argument.
Use it with rowLeave to link the table to another view: the table already highlights the hovered row for the user, and these events let the rest of the app react to the same hover — a detail panel, a matching point on a chart, a pin on a map.
Moving between cells within one row does not re-fire the event; only entering and leaving the row itself does.
<App var.hovered="{null}">
<Table
data='{[...]}'
onRowEnter="(item) => hovered = item"
onRowLeave="() => hovered = null">
<Column bindTo="name"/>
</Table>
</App>Hover a row to see the panel follow it:
rowExpansionDidChange
This event is triggered when the set of expanded table rows changes. Use it with expandedRowIds for controlled row detail state.
Signature: rowExpansionDidChange(expandedRowIds: string[], expandedItems: any[]): void
expandedRowIds: The row IDs that are currently expanded.expandedItems: The expanded row items in data order.
rowLeave
This event is fired when the pointer leaves a table row. The handler receives the row item as its only argument. Pair it with rowEnter to clear whatever that event set.
Signature: rowLeave(item: any): void
item: The table row item the pointer left.
This event fires when the pointer leaves a table row. The handler receives the row's data item as its only argument — the row being left, not the one being entered.
Pair it with rowEnter to clear whatever that event set. See the rowEnter example.
scroll
This event fires as the user scrolls the table. The handler receives an object describing the current scroll state. It is only fired for user-driven scrolls; the table's own programmatic scrolls do not trigger it. Use it together with the atEnd flag and the scrollToBottom() method to implement follow-newest and read-pause behavior, or with visibleRange and itemCount to display a visible row range.
Signature: scroll(event: { scrollTop: number, scrollHeight: number, viewportSize: number, atEnd: boolean, visibleRange: { startIndex: number, endIndex: number }, itemCount: number }): void
event: The scroll state:scrollTop(current scroll offset),scrollHeight(total scrollable size),viewportSize(visible size), andatEnd(true when scrolled to within ~1.5px of the bottom), plusvisibleRangeanditemCount.
This event fires as the user scrolls the table. The event object includes scrollTop, scrollHeight, viewportSize, atEnd, visibleRange, and itemCount.
It is only fired for user-driven scrolls; the table's own programmatic scrolls do not trigger it. Use visibleRange and itemCount to display the currently visible range while the user scrolls.
selectAllAction
This event is triggered when the user presses the select all keyboard shortcut (default: Ctrl+A/Cmd+A) and rowsSelectable is set to true. The component automatically selects all rows before invoking this handler. The handler receives three parameters: the currently focused row (if any), all selected items, and all selected IDs.
Signature: selectAll(row: TableRowContext | null, selectedItems: any[], selectedIds: string[]): void | Promise<void>
row: The currently focused row context, or null if no row is focused. Contains item data, row index, row ID, and selection state.selectedItems: Array of all selected row items. When selectAll is triggered, this contains all table rows.selectedIds: Array of all selected row IDs (as strings). When selectAll is triggered, this contains all row IDs.
selectionDidChange
This event is triggered when the table's current selection (the rows selected) changes. Its parameter is an array of the selected table row items.
Signature: selectionDidChange(selectedItems: any[]): void
selectedItems: An array of the selected table row items.
Of course, if multiple-row selection is not allowed (enableMultipleRowSelection is false), this array will contain zero or one item.
<App var.selection="">
<Text>Current selection (row IDs): [{selection}]</Text>
<Table data='{[...]}'
rowsSelectable="true"
enableMultiRowSelection="true"
onSelectionDidChange="(newSel) => selection = newSel.map(item => item.id).join()" >
<Column bindTo="name" canSort="true"/>
<Column bindTo="quantity" canSort="true"/>
<Column bindTo="unit" canSort="true"/>
</Table>
</App>Click on any of the column headers to trigger a new sorting:
sortingDidChange
This event is fired when the table data sorting has changed. It has two arguments: the column's name and the sort direction. When the column name is empty, the table displays the data list as it received it.
Signature: sortingDidChange(columnName: string, sortDirection: 'asc' | 'desc' | null): void
columnName: The name of the column being sorted.sortDirection: The sort direction: 'asc' for ascending, 'desc' for descending, or null for unsorted.
When the third click clears sorting, the event fires with an empty column name and
the direction that was on screen — the sort the user was just looking at, not
the direction a fresh click would produce. A column whose
defaultSortDirection is descending therefore reports
ascending when cleared from its second stage.
Note the canSort properties on the Column components which enable custom ordering.
<App var.sortedBy="">
<Heading level="h4" value="Table is sorted by: {sortedBy || ''}" paddingLeft="1rem"/>
<Table data='{[...]}'
onSortingDidChange="(by, dir) => sortedBy = (by && dir) ? by + ' | ' + dir : '' " >
<Column bindTo="name" canSort="true"/>
<Column bindTo="quantity" canSort="true"/>
<Column bindTo="unit" canSort="true"/>
</Table>
</App>Click on any of the column headers to trigger a new sorting:
visibleRangeDidChange
This event fires when the range of visible table rows changes — whatever caused it: a user scroll, a programmatic scroll, or content growth. Unlike the scroll event, it is not suppressed during the table's own programmatic scrolls, because consumers of the visible range care about what is visible, not why it became visible. It fires only when the range actually shifts (deduplicated by value).
Signature: visibleRangeDidChange(range: { startIndex: number, endIndex: number }): void
range: The visible range:startIndex(first visible row index) andendIndex(last visible row index), inclusive, in the table's current row order.
This event fires when the visible row range changes. It also fires for non-user-scroll changes, such as initial measurement or programmatic scrolling.
willSort
This event is fired before the table data is sorted. It has two arguments: the column's name and the sort direction. When the method returns a literal false value (and not any other falsy one), the method indicates that the sorting should be aborted.
Signature: willSort(columnName: string, sortDirection: 'asc' | 'desc'): boolean | void
columnName: The name of the column about to be sorted.sortDirection: The intended sort direction: 'asc' for ascending or 'desc' for descending.
The following example uses the willSort event to refuse sorting by name:
<App var.sortedBy="">
<Heading level="h4" value="Table is sorted by: {sortedBy || ''}" paddingLeft="1rem"/>
<Table data='{[...]}'
onWillSort="(by, dir) => by !== 'name'"
onSortingDidChange="(by, dir) => sortedBy = (by && dir) ? by + ' | ' + dir : '' " >
<Column bindTo="name" canSort="true"/>
<Column bindTo="quantity" canSort="true"/>
<Column bindTo="unit" canSort="true"/>
</Table>
</App>Click on any of the column headers to trigger the event.
Though sorting is enabled in the TableColumnnDef component of the "name" column via canSort,
clicking that column header still does not sort because willSort prevents it:
Exposed Methods
clearSelection
This method clears the list of currently selected table rows.
Signature: clearSelection(): void
<App>
<HStack>
<Button label="Select all" onClick="table.selectAll()" />
<Button label="Clear all" onClick="table.clearSelection()" />
<Button label="Select 1" onClick="table.selectId(1)" />
<Button label="Select 2, 4" onClick="table.selectId([2, 4])" />
</HStack>
<Table id="table" data='{[...]}'
rowsSelectable="true"
enableMultiRowSelection="true">
<Column bindTo="name" canSort="true"/>
<Column bindTo="quantity" canSort="true"/>
<Column bindTo="unit" canSort="true"/>
</Table>
</App>collapseRow
Collapses the row with the specified ID.
Signature: collapseRow(id: string | number): void
id: The ID of the row to collapse.
expandRow
Expands the row with the specified ID.
Signature: expandRow(id: string | number): void
id: The ID of the row to expand.
getExpandedRowIds
Returns the IDs of the currently expanded rows.
Signature: getExpandedRowIds(): string[]
getItemCount
This method returns the number of rows in the table's current virtualized row model. For an unpaginated table, this is the number of rows supplied through data or items; for a paginated table, this is the number of rows on the current page.
Signature: getItemCount(): number
Returns the number of rows in the table's current virtualized row model. Use this with getVisibleRange() to build a display such as 234-245 of 1000.
For paginated tables, this count is the number of rows in the current page's virtualized row model.
getSelectedIds
This method returns the list of currently selected table rows IDs.
Signature: getSelectedIds(): Array<string>
(See the example at the clearSelection method)
getSelectedItems
This method returns the list of currently selected table rows items.
Signature: getSelectedItems(): Array<TableRowItem>
(See the example at the clearSelection method)
getVisibleRange
This method returns the currently visible row range as an object with startIndex and endIndex (inclusive, in the table's current row order). Returns { startIndex: -1, endIndex: -1 } when the table is empty or not yet measured. The pull-style counterpart of the visibleRangeDidChange event.
Signature: getVisibleRange(): { startIndex: number, endIndex: number }
Returns the currently visible row range as { startIndex, endIndex }. Indexes are zero-based and inclusive, so add 1 when displaying them to users.
When the table is empty or not yet measured, the method returns { startIndex: -1, endIndex: -1 }. This is the pull-style counterpart of the visibleRangeDidChange event.
<App
scrollWholePage="false"
var.itemCount="{0}"
var.range="{{ startIndex: -1, endIndex: -1 }}">
<Text
variant="strong"
value="{range.startIndex < 0
? 'No rows'
: (range.startIndex + 1) + '-'
+ (range.endIndex + 1) + ' of ' + itemCount}"
/>
<Table
id="table"
height="*"
onScroll="(e) => { range = e.visibleRange; itemCount = e.itemCount }"
onVisibleRangeDidChange="(r) => {
range = r;
itemCount = table.getItemCount()
}"
data="{Array.from({ length: 1000 }, (_, i) => ({
id: i + 1,
name: 'Item ' + (i + 1),
quantity: (i % 25) + 1,
}))}">
<Column bindTo="id" width="90px" />
<Column bindTo="name" />
<Column bindTo="quantity">
<Text height="50px">{$cell}</Text>
</Column>
</Table>
</App><App
scrollWholePage="false"
var.itemCount="{0}"
var.range="{{ startIndex: -1, endIndex: -1 }}">
<Text
variant="strong"
value="{range.startIndex < 0
? 'No rows'
: (range.startIndex + 1) + '-'
+ (range.endIndex + 1) + ' of ' + itemCount}"
/>
<Table
id="table"
height="*"
onScroll="(e) => { range = e.visibleRange; itemCount = e.itemCount }"
onVisibleRangeDidChange="(r) => {
range = r;
itemCount = table.getItemCount()
}"
data="{Array.from({ length: 1000 }, (_, i) => ({
id: i + 1,
name: 'Item ' + (i + 1),
quantity: (i % 25) + 1,
}))}">
<Column bindTo="id" width="90px" />
<Column bindTo="name" />
<Column bindTo="quantity">
<Text height="50px">{$cell}</Text>
</Column>
</Table>
</App>isRowExpanded
Returns whether the row with the specified ID is expanded.
Signature: isRowExpanded(id: string | number): boolean
id: The ID of the row to inspect.
preserveStateOnNextDataRefresh
Preserve the current table view state for the next data refresh, even when dataRefreshMode is reset. Optional operation metadata controls post-refresh scroll behavior.
Signature: preserveStateOnNextDataRefresh(options?: { operation?: "insert" | "delete" | "update", scrollTarget?: string | number | "first-inserted" | "preserve" }): void
scrollToBottom
This method scrolls the table to the bottom.
Signature: scrollToBottom(): void
See the getVisibleRange example for displaying the visible range while scrolling.
scrollToId
This method scrolls the table to a specific row. The method accepts a row ID as a parameter.
Signature: scrollToId(id: string): void
id: The ID of the row to scroll to.
See the getVisibleRange example.
scrollToIndex
This method scrolls the table to a specific row index. The method accepts an index as a parameter.
Signature: scrollToIndex(index: number): void
index: The row index to scroll to.
See the getVisibleRange example.
scrollToTop
This method scrolls the table to the top.
Signature: scrollToTop(): void
See the getVisibleRange example.
selectAll
This method selects all the rows in the table. This method has no effect if the rowsSelectable property is set to false.
Signature: selectAll(): void
(See the example at the clearSelection method)
selectId
This method selects the row with the specified ID. This method has no effect if the rowsSelectable property is set to false. The method argument can be a single id or an array of them.
Signature: selectId(id: string | Array<string>): void
id: The ID of the row to select, or an array of IDs to select multiple rows.
(See the example at the clearSelection method)
toggleRowExpansion
Toggles the expanded state of the row with the specified ID.
Signature: toggleRowExpansion(id: string | number): void
id: The ID of the row to toggle.
Parts
The component has some parts that can be styled through layout properties and theme variables separately:
pagination: The pagination controls container.table: The main table container.