Use the Table block to:
Show a list of records users can scan, sort, filter and page through.
Let users act on records via per-row buttons or bulk actions over many selected rows.
Let users edit records in place, with edits batched into a single save.
Give users saved views, grouping or a summary footer over the data.


Note: Table vs Repeatable: Use a Repeatable when every record should render as its own free-form card of blocks. Use a Table when records belong in columns and users need sorting, filtering, pagination, selection or inline editing.
Data Binding
A table's rows come from one of two Source modes, chosen under Inspector → Content → Source.
| Source Mode | How rows are supplied | What the table does for you |
Object | Pick a platform object under Select Object; the table queries it automatically | Applies server-side filters & sorts; computes total record count and pagination totals |
Mapped | Bind your own data (API result, variable, another block) under Data Source | Nothing — you own the query, pagination offset/size, and must supply Total Records yourself |
Primary Key
The Primary Key field uniquely identifies each row. It is required for row selection, inline editing, drag-reordering, and saved views to work correctly. Set it under Inspector → Content → Primary Key.
Warning: Changing the data source rebuilds columns. Selecting or changing the data source regenerates the column list from the response and replaces any custom configuration — column names, formats, widths and editability you set up are lost. Only text, number, and boolean fields from the response become columns automatically. Reconfigure columns after switching sources.
Content Properties
Property | Type | Req? | Where to Set | Description |
|---|---|---|---|---|
|
| Optional | Inspector → Content → Source | Whether rows come from a platform object or from manually bound data |
|
| Conditional | Inspector → Content → Select Object | The platform object whose records fill the table. Visible when Source = Object |
|
| Conditional | Inspector → Content → Data Source | The data bound as the table's rows. Visible when Source = Mapped |
|
| Required | Inspector → Content → Primary Key | The field that uniquely identifies each row. Required for selection and inline editing |
|
| Optional | Inspector → Content → Columns | The table's columns and their types — see Column Types |
|
| Optional | Inspector → Content → Row Selection | Whether users can select rows. New tables start with Single — see Row Actions & Selection |
|
| Optional | Inspector → Content → Row Actions | Per-row buttons rendered in the actions column |
|
| Optional | Inspector → Content → Bulk Actions | Actions over selected rows; requires Row Selection = Multiple |
Appearance Properties
Property | Type | Default | Description |
|---|---|---|---|
Grid Lines ( | 7 options | Both on new tables | Which borders the grid draws: Both, Both Between, Horizontal, Horizontal Between, Vertical, Vertical Between, or None |
Row Height ( | Compact | Comfortable | Spacious | Compact on new tables | Row density: 36px (Compact), 52px (Comfortable), 92px (Spacious) |
Hide Header ( | boolean | false | Hides the header row entirely |
Wrap Column Header ( | boolean | false | Wraps long header labels instead of truncating. Visible when Hide Header is off |
Empty Message ( | string | "No data found" | Text shown when the table has no rows and no filter is active |
Styles → Cell Background / Cell Text | color | — | Background and text color of body cells |
Styles → Cell Padding | spacing | 6px top/bottom, 12px left/right | Padding inside each body cell |
Header Background / Header Text | color | Light brand background, primary text | Background and text color of the header row |
Header Padding | spacing | 6px top/bottom, 12px left/right | Padding inside each header cell |
Grid Line Color ( | color | Light gray | Color of the grid lines |
Row Hover Color ( | color, condition-capable | — | Row background while hovered; can vary per row by condition |
Selected Row Hover Color ( | color, condition-capable | — | Background of a selected row while hovered; can vary per row by condition |
Note: Empty State slot vs Empty Message: A block in the Empty State slot replaces both the Empty Message and the "All records are filtered" message. If a search or filter is active with zero results, the fixed message "All records are filtered" shows instead of your custom Empty Message — only the slot overrides it.
Add-ons
Add-ons live under Inspector → Content → Add-ons. Each opens its own detail panel.
Add-on | Default | What it adds |
|---|---|---|
Toolbar | Enabled, title "Table Title" | Title, record count, filter, search, sort, column visibility, views — see Toolbar & Views |
Pagination | Page based, 30/page | Page or scroll-based paging |
Row Ordering | Enabled | Drag-to-reorder rows; produces a |
Column Ordering | Enabled | Drag-to-reorder columns |
Column Resizing | Enabled | Drag column borders to resize |
Sub Rows | Off | Expandable nested child rows — see Row Actions & Selection |
Detail Panel | Off | Expanding a row renders a block slot beneath it. Mutually exclusive with Sub Rows |
User State Settings | Remember on | Persists the user's paging, filters and column layout between visits |
Save Action | Off | The Save/Cancel bar for inline edits — appears only once a column is editable |
Summary | Off | A summary footer row — appears only once a column has a summary configured |
Pagination Add-on
Property | Type | Default | Description |
|---|---|---|---|
Type ( | Page based | Scroll based | Page based | Numbered pages or infinite scroll |
Page Size ( | number | 30 | Rows per page |
Page Size Mode ( | Fixed | User Selectable | Fixed | Whether users can change the page size. Page based only |
Total Records ( | number, bindable | — | Total row count. Required for Mapped sources; auto-computed for Object sources |
Initial Page ( | number | 1 | Which page loads first. Page based only |
Warning: Mapped sources need Total Records. With a Mapped source and page-based pagination, the table cannot know the total row count — bind Total Records yourself or the page navigation has no total to count against.
Events
Configure these under Inspector → Content → Interactions (On Save under the Save Action add-on).
Event | Trigger | Fires when |
|---|---|---|
On Select Row | A row is selected | Always |
On Change Row Selection | A row's checkbox is toggled | Multiple selection only |
On Click Cell | A cell is clicked | Always |
On Right Click Cell | A cell is right-clicked | Always |
On Change Cell Value | An editable cell's value changes | Editable columns |
On Change Row Order | A row is dragged to a new position | Row Ordering enabled |
On Page Change | The user moves to another page | Page-based pagination |
On Receive Notification | A notification targets the table | Always |
On Save | User clicks Save on the changeset bar | Save Action add-on configured |
Note: Clicking a row action also sets {{ id.selectedRow }} and {{ id.selectedRowKey }} before the action's own event runs, so the handler and anything bound to selection always sees the clicked row.
Methods
Wire any event to a Trigger Component Method action, pick the table under Block ID, the method under Method Name, and fill Method Payload when required. Methods only run while the table is visible — calling a method on a hidden table does nothing and the call is not queued.
Method | Params | Available when | What it does |
|---|---|---|---|
| — | Always | Re-runs the table's data query |
| fileName, fileType, sheetName, exportHiddenColumns | Always | Exports to CSV, XLS, or XLSX |
| — | Always | Clears the current row selection |
| rowId | Single selection | Selects one row by primary key |
| rowIds | Multiple selection | Selects rows by primary key |
| — | Multiple selection | Selects every row on the current page |
| changesetCursor (optional) | Editable columns | Discards pending inline edits (all, or up to cursor position) |
| changesetCursor (optional) | Row Ordering enabled | Discards pending drag-and-drop row reorders (all, or up to cursor position) |
| — | Sub Rows enabled | Expands or collapses every parent row |
| searchText (apply only) | Search action configured | Set or clear the search term programmatically |
| — | Page-based pagination | Moves one page forward or back — use these to wire a custom Pagination slot |
| pageNumber | Page-based pagination | Jumps to the given page (1 or higher) |
| pageSize | Page-based pagination | Changes how many rows each page shows |
| name | Views toolbar action configured | Saves the current layout as a new view |
| id | Views toolbar action configured | Updates or deletes the view with that id |
Exposed State
Read these from anywhere on the page as {{ id.* }} where id is the table's block ID.
| State key | Type | Description |
{{ id.selectedRow }} | object | Data of the last selected row (Single selection) |
{{ id.selectedRowKey }} | string | Primary key of the last selected row (Single selection) |
{{ id.selectedRows }} | array | Data of all selected rows (Multiple selection) |
{{ id.selectedRowKeys }} | array | Primary keys of all selected rows (Multiple selection) |
{{ id.currentData }} | array | Rows currently rendered, with pending edits already applied |
{{ id.filters }} | object | Current search, sort and filter state |
{{ id.changesetList }} | array | Pending inline edits as a list ready for an update call |
{{ id.rowOrderChangesetList }} | array | Pending drag-reorder changes |
{{ id.activeView }} | object | Active saved view: id, name, isDirty |
{{ id.views }} | array | Available saved views |
{{ id.content.page.size }} | number | Current page size |
{{ id.content.page.offset }} | number | Index of the first row on the current page |
{{ id.context.currentRow }} | object | The row being rendered — only valid inside the table |
{{ id.context.currentRowIndex }} | number | The row's position (0-indexed) — only valid inside the table |
Warning: context bindings (currentRow, currentRowIndex) only resolve inside the table — in a row action's settings, a cell value, or a block placed in a custom cell. From a button elsewhere on the page, use {{ id.selectedRow }} instead.
Behavior & Gotchas
Bulk actions lock selection to Multiple
While any bulk action is configured, the Single and None selection modes are disabled in the inspector. Remove the bulk actions first if you need Single or None.
No built-in way to add or delete rows
The table has no add-row or delete-row control and no method to insert or remove a row. With a Mapped source, change the bound data itself. With an Object source, run a create/delete call from a button or row action, then call refetchData.
The header stays put; the grid scrolls
The header row is sticky by default. The grid scrolls vertically inside a capped container while the header stays visible. Horizontal scrolling appears automatically when columns are wider than the block. Turn on a column's Grow setting so columns share leftover width instead of overflowing.
Methods do nothing on hidden tables
Calling any method on a hidden table (behind a visibility condition, on an inactive tab, inside a closed drawer) silently does nothing — the call is not queued. Trigger methods after the table is shown, not before.
User State Settings remembers layout and paging, not selection
With User State Settings on (the default), each user's page number, filters, sort, search, column order and widths are persisted. Row selection and pending edits are not saved. Turn on Reset When Hidden to clear state on hide.
Related Blocks
Block | Relationship |
|---|---|
Often paired with a table to create or edit the selected record | |
An alternative column-based view of the same records | |
Renders one free-form card per record — use when each record needs its own layout | |
Typically opened from a table row action or On Select Row event |