Unify Logo Footer.svg
Unify Applications
Logo
Table Overview

Table Overview

Logo

10 mins READ

When to Use the Table Block

  • 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 ModeHow rows are suppliedWhat the table does for you
ObjectPick a platform object under Select Object; the table queries it automaticallyApplies server-side filters & sorts; computes total record count and pagination totals
MappedBind your own data (API result, variable, another block) under Data SourceNothing — 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

PropertyTypeReq?Where to SetDescription
source"Object" | "Mapped"OptionalInspector → Content → SourceWhether rows come from a platform object or from manually bound data
entityIdobjectConditionalInspector → Content → Select ObjectThe platform object whose records fill the table. Visible when Source = Object
dataSourceIddata, bindableConditionalInspector → Content → Data SourceThe data bound as the table's rows. Visible when Source = Mapped
identifierfield keyRequiredInspector → Content → Primary KeyThe field that uniquely identifies each row. Required for selection and inline editing
columnscolumn listOptionalInspector → Content → ColumnsThe table's columns and their types — see Column Types
rowSelection"None" | "Single" | "Multiple"OptionalInspector → Content → Row SelectionWhether users can select rows — see Row Selection
rowActionsaction listOptionalInspector → Content → Row ActionsPer-row buttons rendered in the actions column
bulkActionsaction listOptionalInspector → Content → Bulk ActionsActions over selected rows; requires Row Selection = Multiple

Appearance Properties

PropertyTypeDefaultDescription
gridLineAxis7 optionsWhich borders the grid draws: Both, Both Between, Horizontal, Horizontal Between, Vertical, Vertical Between, or None
rowHeight"Compact" | "Comfortable" | "Spacious"Row density: 36px (Compact), 52px (Comfortable), 92px (Spacious)
hideHeadersbooleanfalseHides the header row entirely
wrapColumnHeaderbooleanfalseWraps long header labels instead of truncating. Visible when Hide Header is off
emptyMessagestring"No data found"Text shown when the table has no rows and no filter is active
rowHoverColorcolor, condition-capableRow background 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-onDefaultWhat it adds
ToolbarEnabled, title "Table Title"Title, record count, filter, search, sort, column visibility, views — see Toolbar & Views
PaginationPage based, 30/pagePage or scroll-based paging
Row OrderingEnabledDrag-to-reorder rows; produces a rowOrderChangesetList
Column OrderingEnabledDrag-to-reorder columns
Column ResizingEnabledDrag column borders to resize
Sub RowsOffExpandable nested child rows — see Row Selection & Expansion
Detail PanelOffExpanding a row renders a block slot beneath it. Mutually exclusive with Sub Rows
User State SettingsRemember onPersists the user's paging, filters and column layout between visits
Save ActionOffThe Save/Cancel bar for inline edits — appears only once a column is editable
SummaryOffA summary footer row — appears only once a column has a summary configured

Pagination

PropertyTypeDefaultDescription
type"Page based" | "Scroll based"Page basedNumbered pages or infinite scroll
sizenumber30Rows per page
pageSizeMode"Fixed" | "User Selectable"FixedWhether users can change the page size. Page based only
totalnumber, bindableTotal row count. Required for Mapped sources; auto-computed for Object sources
initialPagenumber1Which 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).

EventTriggerFires when
On Select RowA row is selectedAlways
On Change Row SelectionA row's checkbox is toggledMultiple selection only
On Click CellA cell is clickedAlways
On Change Cell ValueAn editable cell's value changesEditable columns
On Change Row OrderA row is dragged to a new positionRow Ordering enabled
On Page ChangeThe user moves to another pagePage-based pagination
On Receive NotificationA notification targets the tableAlways
On SaveUser clicks Save on the changeset barSave 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.

MethodParamsAvailable whenWhat it does
refetchDataAlwaysRe-runs the table's data query
exportDatafileName, fileType, sheetName, exportHiddenColumnsAlwaysExports to CSV, XLS, or XLSX
clearRowSelectionAlwaysClears the current row selection
selectRowrowIdSingle selectionSelects one row by primary key
selectRowsrowIdsMultiple selectionSelects rows by primary key
selectAllRowsMultiple selectionSelects every row on the current page
clearChangesetchangesetCursor (optional)Editable columnsDiscards pending inline edits (all, or up to cursor position)
expandAllRows / collapseAllRowsSub Rows enabledExpands or collapses every parent row
applyKeywordSearch / clearKeywordSearchsearchText (apply only)Search action configuredSet or clear the search term programmatically

Exposed State

Read these from anywhere on the page as {{ id.* }} where id is the table's block ID.

State keyTypeDescription
{{ id.selectedRow }}objectData of the last selected row (Single selection)
{{ id.selectedRowKey }}stringPrimary key of the last selected row (Single selection)
{{ id.selectedRows }}arrayData of all selected rows (Multiple selection)
{{ id.selectedRowKeys }}arrayPrimary keys of all selected rows (Multiple selection)
{{ id.currentData }}arrayRows currently rendered, with pending edits already applied
{{ id.filters }}objectCurrent search, sort and filter state
{{ id.changesetList }}arrayPending inline edits as a list ready for an update call
{{ id.rowOrderChangesetList }}arrayPending drag-reorder changes
{{ id.activeView }}objectActive saved view: id, name, isDirty
{{ id.views }}arrayAvailable saved views
{{ id.content.page.size }}numberCurrent page size
{{ id.content.page.offset }}numberIndex of the first row on the current page
{{ id.context.currentRow }}objectThe row being rendered — only valid inside the table
{{ id.context.currentRowIndex }}numberThe 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.

Common Patterns

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.

Frequently Asked Questions

What is the difference between an Object source and a Mapped source?

An Object source points the table at a platform object (a stored business entity with records): the table runs the query, applies toolbar filter/search/sort server-side, and computes pagination totals for you. A Mapped source means you bind the rows yourself — from an API, a variable, another block — and you own the query, the paging inputs ({{ id.content.page.offset }} and {{ id.content.page.size }}), and the Total Records count. Use Object when your data is a platform object; use Mapped for external APIs and computed data.

When I select a row and open a drawer, why does the drawer show nothing?

Binding the drawer's fields to {{ table1.selectedRow }} fills the content but does not open the drawer. You need two steps: bind the content, and wire the table's On Select Row event to the drawer's Show method via a Trigger Component Method action. Without that method call, the drawer never opens.

Why does my mapped table show the same rows on every page?

Your data source is returning rows in an unstable order, or you are not passing the current offset to it. The table never slices data itself — it asks the source for each page by offset and size via {{ id.content.page.offset }} and {{ id.content.page.size }}. Bind those into your API call's parameters and sort the source deterministically (add a tiebreaker like an id) so page 2 today is the same as page 2 later.

Can I have more than one Table on the same page?

Yes — each Table block has its own Block ID and its own independent state. You can wire them together (bind the second table's data source to the first table's {{ table1.selectedRow.id }} as a filter parameter) to build master-detail layouts.

Why are my columns missing after I switched the data source?

Changing the data source regenerates the column list from the new response and replaces everything you configured — column names, formats, widths, editability are all reset. This is by design. Reconfigure columns after switching sources, not before.

BlockRelationship
ListA simpler, card-style list without columns, sorting or inline editing
FormOften paired with a table to create or edit the selected record
KanbanAn alternative column-based view of the same records
RepeatableRenders one free-form card per record — use when each record needs its own layout
Drawer / ModalTypically opened from a table row action or On Select Row event