Skip to content

App Builder Actions

Action system reference for user interactions

Actions define what happens when users interact with components. They enable:

  • Navigation between pages
  • Workflow execution
  • Variable updates
  • Data refresh
  • Form submission

Navigate to another page or external URL.

{
"type": "navigate",
"navigateTo": "/customers/{{ row.id }}"
}
PropertyTypeDescription
navigateTostringTarget path (supports expressions)

Examples:

// Static path
{ "type": "navigate", "navigateTo": "/dashboard" }
// Dynamic path with row data
{ "type": "navigate", "navigateTo": "/users/{{ row.id }}/edit" }
// Path with query parameters
{ "type": "navigate", "navigateTo": "/search?q={{ variables.query }}" }
// Path with multiple segments
{ "type": "navigate", "navigateTo": "/org/{{ user.orgId }}/projects/{{ row.projectId }}" }

Execute a backend workflow.

{
"type": "workflow",
"workflowId": "create_customer",
"actionParams": {
"name": "{{ field.customerName }}",
"email": "{{ field.customerEmail }}"
}
}
PropertyTypeDescription
workflowIdstringWorkflow identifier
actionParamsobjectParameters passed to workflow (supports expressions)

Examples:

// Simple workflow call
{
"type": "workflow",
"workflowId": "refresh_data"
}
// With static parameters
{
"type": "workflow",
"workflowId": "update_status",
"actionParams": {
"status": "approved"
}
}
// With dynamic parameters
{
"type": "workflow",
"workflowId": "process_order",
"actionParams": {
"orderId": "{{ row.id }}",
"quantity": "{{ field.quantity }}",
"userId": "{{ user.id }}"
}
}

Collect all form field values and submit to a workflow.

{
"type": "submit",
"workflowId": "save_form",
"actionParams": {
"formType": "contact",
"submittedBy": "{{ user.id }}"
}
}
PropertyTypeDescription
workflowIdstringWorkflow to receive form data
actionParamsobjectAdditional parameters merged with field values

The workflow receives all field values plus any additional actionParams:

@workflow(name="save_form")
async def save_form(
# Form fields (from fieldId)
customerName: str,
customerEmail: str,
quantity: int,
# Additional params
formType: str,
submittedBy: str
):
...

Update a page-level variable.

{
"type": "set-variable",
"variableName": "selectedCustomerId",
"variableValue": "{{ row.id }}"
}
PropertyTypeDescription
variableNamestringVariable name to set
variableValueanyValue to assign (supports expressions)

Examples:

// Set static value
{
"type": "set-variable",
"variableName": "isEditing",
"variableValue": true
}
// Set from row data
{
"type": "set-variable",
"variableName": "selectedId",
"variableValue": "{{ row.id }}"
}
// Set from workflow result
{
"type": "set-variable",
"variableName": "lastCreatedId",
"variableValue": "{{ workflow.result.id }}"
}
// Clear a variable
{
"type": "set-variable",
"variableName": "selectedId",
"variableValue": null
}

Reload data from a data source.

{
"type": "refresh-table",
"dataSourceKey": "customers"
}
PropertyTypeDescription
dataSourceKeystringID of the data source to refresh

Use after workflows that modify data to update the UI.

Trigger a custom action handler (advanced use).

{
"type": "custom",
"customActionId": "exportPdf",
"actionParams": {
"format": "A4",
"orientation": "portrait"
}
}
PropertyTypeDescription
customActionIdstringCustom action identifier
actionParamsobjectParameters for the handler

After a workflow completes, onComplete actions execute in sequence:

{
"actionType": "workflow",
"workflowId": "create_customer",
"actionParams": { "name": "{{ field.name }}" },
"onComplete": [
{
"type": "set-variable",
"variableName": "lastCreatedId",
"variableValue": "{{ workflow.result.id }}"
},
{
"type": "refresh-table",
"dataSourceKey": "customers"
},
{
"type": "navigate",
"navigateTo": "/customers/{{ workflow.result.id }}"
}
]
}
TypeDescription
navigateGo to another page
set-variableUpdate a page variable
refresh-tableReload a data source

Add confirmation before destructive actions:

{
"label": "Delete",
"variant": "destructive",
"onClick": {
"type": "workflow",
"workflowId": "delete_customer",
"actionParams": { "id": "{{ row.id }}" }
},
"confirm": {
"title": "Delete Customer",
"message": "Are you sure you want to delete {{ row.name }}? This cannot be undone.",
"confirmLabel": "Delete",
"cancelLabel": "Cancel"
}
}
PropertyTypeDefaultDescription
titlestringrequiredDialog title
messagestringrequiredConfirmation message (supports expressions)
confirmLabelstringConfirmConfirm button text
cancelLabelstringCancelCancel button text

Buttons support all action types:

{
"type": "button",
"props": {
"label": "Create Order",
"actionType": "workflow",
"workflowId": "create_order",
"actionParams": {
"items": "{{ variables.cartItems }}",
"customer": "{{ field.customerId }}"
},
"onComplete": [
{ "type": "navigate", "navigateTo": "/orders/{{ workflow.result.orderId }}" }
]
}
}
{
"type": "button",
"props": {
"label": "Go to Settings",
"actionType": "navigate",
"navigateTo": "/settings"
}
}
{
"type": "button",
"props": {
"label": "Save",
"actionType": "submit",
"workflowId": "save_profile",
"variant": "default"
}
}

{
"type": "data-table",
"props": {
"dataSource": "customers",
"onRowClick": {
"type": "navigate",
"navigateTo": "/customers/{{ row.id }}"
}
}
}

Alternative row click behaviors:

// Set variable on click
{
"onRowClick": {
"type": "set-variable",
"variableName": "selectedCustomer",
"variableValue": "{{ row }}"
}
}
// Select row (for multi-select tables)
{
"onRowClick": {
"type": "select"
}
}

Actions in each row:

{
"rowActions": [
{
"label": "Edit",
"icon": "pencil",
"onClick": {
"type": "navigate",
"navigateTo": "/customers/{{ row.id }}/edit"
}
},
{
"label": "Archive",
"icon": "archive",
"visible": "{{ row.status == 'active' }}",
"onClick": {
"type": "workflow",
"workflowId": "archive_customer",
"actionParams": { "id": "{{ row.id }}" }
},
"confirm": {
"title": "Archive Customer",
"message": "Archive {{ row.name }}?"
}
}
]
}

Actions in the table header:

{
"headerActions": [
{
"label": "Add Customer",
"icon": "plus",
"onClick": {
"type": "navigate",
"navigateTo": "/customers/new"
}
},
{
"label": "Export All",
"icon": "download",
"onClick": {
"type": "workflow",
"workflowId": "export_customers"
}
}
]
}

{
"type": "stat-card",
"props": {
"title": "Total Revenue",
"value": "${{ data.stats.revenue }}",
"onClick": {
"type": "navigate",
"navigateTo": "/reports/revenue"
}
}
}

{
"type": "modal",
"props": {
"title": "Edit Customer",
"footerActions": [
{
"label": "Cancel",
"variant": "outline",
"closeOnClick": true
},
{
"label": "Save",
"actionType": "submit",
"workflowId": "update_customer",
"closeOnClick": true
}
]
}
}
PropertyTypeDefaultDescription
closeOnClickbooleanfalseClose modal after action completes

Actions after embedded form submission:

{
"type": "form-embed",
"props": {
"formId": "contact-form",
"onSubmit": [
{
"type": "set-variable",
"variableName": "formSubmitted",
"variableValue": true
},
{
"type": "refresh-table",
"dataSourceKey": "submissions"
}
]
}
}

User clicks button
Show loading state
Execute workflow with actionParams
Receive workflow result
Execute onComplete actions (in order)
Clear loading state
User clicks submit button
Collect all field values
Merge with actionParams
Execute workflow
Execute onComplete actions
User clicks action with confirm
Show confirmation dialog
User clicks Confirm → Execute action
User clicks Cancel → Do nothing

  1. Use onComplete for chaining: Don’t rely on timing; use onComplete to sequence actions after workflows.

  2. Refresh after mutations: After create/update/delete workflows, add refresh-table to update the UI.

  3. Confirm destructive actions: Always add confirm for delete and irreversible operations.

  4. Keep actionParams minimal: Pass only what the workflow needs; avoid sending entire objects.

  5. Use variables for complex state: For multi-step interactions, use set-variable to track state across actions.

  6. Test navigation paths: Ensure dynamic paths resolve correctly with expected data.