Unify Applications
Logo
Inline Editing & Changesets

Inline Editing & Changesets

Logo

7 mins READ

Inline editing lets users change cell values directly in a Table block. Edits aren't written anywhere by themselves: they collect in the table's changeset — the pending changes, tracked per row and field — until the user clicks Save in the floating bar and your On Save handler runs your update call.

Making a Column Editable

The Editable toggle is shown in a column's settings when the column's type is one of the editable types: Text, Number, Percent, Currency, Tag, Boolean, Date Time, Date, Time, Mapped. In a nested table, only top-level columns can be editable.

The toggle is greyed out until both of these are set. Its tooltip tells you which one is missing.

  1. The table has a Primary Key configured (edits are tracked per row key).

  2. The column has a Field Key set.

unify-applications-inline-editing-and-changesets-01-editable-needs-primary-key.png
unify-applications-inline-editing-and-changesets-01-editable-needs-primary-key.png

The toggle also accepts conditions, so a column can be editable only for specific rows — for example only while {{ orders.context.currentRow.status }} === 'draft'.

Edit PropertyDefaultDescription
EditableoffBoolean or condition. Turns on inline editing always or per row
Placeholder Text—Hint shown in the empty edit control
Validity Conditions—Rules an entered value must pass. Failing values are rejected on commit and never enter the changeset
Step size (in minutes)15Time columns only: minute increments for the time picker dropdown (does not constrain typed input)
Date Selection Limits—Date columns only: restrict the selectable date range

unify-applications-inline-editing-and-changesets-02-editable-on.png
unify-applications-inline-editing-and-changesets-02-editable-on.png

The Save Action Add-On

Once at least one column is editable, a Save Action add-on appears under Inspector → Content → Add-ons.

unify-applications-inline-editing-and-changesets-03-save-action-add-on.png
unify-applications-inline-editing-and-changesets-03-save-action-add-on.png

PropertyDefaultDescription
On Save (event)—The handler that runs when the user clicks Save. Wire your update call here, binding {{ id.changesetList }} as its input
Disabled—Condition to disable the Save button
Loading—Condition to show a spinner on the Save button
Clear changeset on successful savetrueClears pending changes automatically once the save's data refresh completes

Warning: Without an On Save handler, there is no Save bar. The floating Save/Cancel bar only renders when an On Save handler is configured. Without one, users can edit cells, the edits pile up in the changeset, but nothing on screen offers to save or cancel them. The inspector shows a warning in this case.

The Typical Save Flow

  1. The user edits one or more cells. Each edit fires On Change Cell Value (table-level) and the column's own change event.

  2. A dark floating bar appears at the bottom of the table: "N changes", Cancel, Save. The count is the number of changed fields, not rows.

  3. Cancel discards all pending edits. Save fires your On Save event — read {{ id.changesetList }} there and pass it to your update call.

  4. End the On Save handler by calling the table's refetchData method to reload the grid.

  5. With Clear changeset on successful save on (the default), the pending changes clear automatically once the data refresh completes.

Undo and redo

With a table cell selected in a running app or preview, press Ctrl/Cmd+Z to undo a pending edit. Press Ctrl+Y, Cmd+Y or Ctrl/Cmd+Shift+Z to redo it. The table keeps up to 20 steps. Undo and redo are not available in the builder canvas.

Each undo or redo fires On Change Cell Value. Cancel, Save and clearing the changeset empty the undo history.

What the Changeset Exposes

BindingTypeDescription
{{ id.changesetList }}arrayPending changes as a list ready for an update call. The recommended binding
{{ id.changesetMap }}objectThe same edits keyed by row primary-key value, then field key. Resolves at runtime only — not surfaced as a first-class binding suggestion
{{ id.rowOrderChangesetList }}arrayPending drag-reorder changes — each entry has the row's primary key and its target index

changesetList Entry Shape

Each entry in changesetList names the row under a property named after your Primary Key field, plus an updateFields array with one item per changed field:

[ { "id": "ord-1042", "updateFields": [ { "fieldName": "status", "actionType": "SET", "value": "Shipped" } ] } ]

This is one row with one changed field, in a table whose Primary Key is id. actionType is always SET.

Warning: Changeset values are always text. Each value in updateFields is a text string regardless of the column's real type — a number or date edit still arrives as text. Convert it on the way into your update call if the target expects a typed value.

Using changesetMap for Pending Values in Other Columns

changesetMap is keyed by the row's primary-key value, then the field key. It only holds values that differ from the original data (unedited rows have no entry). Use it to show a pending value in a different column before saving:

{{ orders.changesetMap?.[orders.context.currentRow.id]?.status ?? orders.context.currentRow.status }}

This reads the current row's pending status value (the row key comes from the table's row context) and falls back to the saved value when the row has no pending edit. Here orders is the table's ID, id its Primary Key field and status the edited column's Field Key.

The Changeset Cursor

A changeset cursor is a position in changesetList. Calling clearChangeset(N) removes the first N entries and keeps the rest — useful when you process edits one batch at a time without an On Save handler.

Note: Without an On Save handler, the changeset grows as a log. Every edit appends a new entry (instead of merging per row). Use the cursor to consume and trim: read the current list, process the first N entries, then call clearChangeset(N). Any edits made while the call was running survive at position N and later.

Copy, Cut and Paste

Click a cell or select a range of cells, then press Ctrl/Cmd+C to copy or Ctrl/Cmd+X to cut. While a range is selected, copy and cut apply to the whole range.

Users can also paste a block of cells copied from Excel or Google Sheets: click a cell to focus it, then press Ctrl/Cmd+V. The clipboard is read as a grid (tab-separated columns, one row per line) and applied as bulk edits starting at the focused cell. Only cells whose column is editable receive a value. Pasted values enter the changeset exactly as typed edits do.

Row Ordering Changeset

When the Row Ordering add-on is enabled, users can drag rows to new positions. Pending reorder moves accumulate in {{ id.rowOrderChangesetList }}. Each entry has:

Field

Description

<your Primary Key field> (e.g. id)

The row's primary key value, under a property named after your Primary Key field

targetIndex

The row's new position (0-indexed)

For example, with a Primary Key field named id: [ { "id": "42", "targetIndex": 0 } ]

Process and clear reorder changes with clearRowOrderChangeset(cursor?) — same cursor semantics as clearChangeset.

Behavior & Gotchas

Auto-clear waits for the data refresh, not the save call

"Clear changeset on successful save" clears once the table's data source finishes its next refresh after On Save fires — typically the refetchData call. If On Save never refreshes the data, pending changes linger. If it fails mid-way but a refresh still happens, they clear anyway. Bind {{ id.changesetList }} as your update call's input in the same step — do not read it in a later step after the save, because auto-clear will have emptied it by then.

Editing a cell back to its original value removes it from the pending list

The pending-values map compares each edit against the row's original data. Type the old value back and the entry disappears, lowering the change count. The user cannot "save" a no-op edit through the changeset.

One cell edit fires two change events

An edit emits both the table-level On Change Cell Value and the edited column's own change event. Wire your handler at one level only to avoid running it twice per edit.

Validation runs on commit, not on every keystroke

Validity Conditions run when the user commits the cell (Enter, Tab, or click away). A failing value shows an error on the cell and keeps focus there; it never enters the changeset. Save is never blocked by invalid input because invalid values never reach it.

Second click on a non-editable cell shows "This cell can't be edited"

The first click on any cell focuses it. A second interaction with a non-editable cell (click, Enter, or typing) makes the cell shake briefly and shows an anchored tooltip for about a second. This is not configurable and cannot be turned off; the only exception is Custom columns which never show it.

Page

Relationship

Column Types

Which types are editable and their edit-time options

Table Overview

Primary key, events and methods in full

Toolbar & Views

Save Action add-on and its relationship to the toolbar

Inline Edit Changeset

A shorter walkthrough of the same feature, written for a bulk-edit use case

FAQs

I edited cells but no Save bar appeared. What is missing?

Configure an On Save handler under Add-ons → Save Action → Interactions. The floating Save/Cancel bar only renders when an On Save handler is wired. Without a handler, edits accumulate silently in the changeset with no way for the user to save or discard them.

My pending changes don't clear after my save runs. Why?

"Clear changeset on successful save" waits for the table's data to refresh — not for your save call to complete. Make sure the last action in your On Save handler is a Trigger Component Method → refetchData. If you turned auto-clear off, call clearChangeset explicitly in your handler.

Can users paste a range from Excel into the table?

Yes — focus a cell and press Ctrl/Cmd+V. The clipboard grid is applied as bulk pending edits, editable columns only. Non-editable columns in the paste range are skipped. You can also copy (Ctrl/Cmd+C) or cut (Ctrl/Cmd+X) a cell or a selected range of cells.

My changeset list keeps growing and never resets. What is happening?

This happens when no On Save handler is configured. Without one, the changeset behaves as an append-only log — every edit adds a new entry. Either wire an On Save handler (edits then merge per row and the Save bar appears), or use the changeset cursor pattern to consume and trim the list yourself programmatically.

How do I let users reorder rows and persist the new order?

Enable the Row Ordering add-on. Drag moves accumulate in {{ id.rowOrderChangesetList }}, where each entry has the row's primary key and its targetIndex. In an On Save handler (or from a custom Save button), pass the reorder list to your update call, then call refetchData and clearRowOrderChangeset to clean up.