ObjectStackObjectStack

Action Triggers

In ObjectUI, interactivity is defined by Actions, not functions.

Because the UI Definition must be strictly serializable (JSON), we cannot pass JavaScript functions like onClick={() => alert('Hello')}. Instead, we declare Action Objects that the ObjectUI Runtime Engine interprets and executes.

1. The Action Protocol

An Action is a JSON object describing what should happen. Events like onClick or onSuccess accept either a single Action or an Chain of Actions (Array).

Basic Structure

interface ActionDef {
  /** The operation identifier */
  action: string;
  
  /** Arguments for the operation */
  params?: Record<string, any>;
  
  /** Ask for user confirmation before executing */
  confirm?: {
    title: string;
    message: string;
    variant?: 'danger' | 'info';
  };
  
  /** Condition to execute (Expression) */
  when?: string;
}

Example: A Delete Button

{
  "type": "button",
  "props": {
    "label": "Delete Project",
    "variant": "destructive",
    "onClick": [
      {
        "action": "api.mutation",
        "confirm": {
          "title": "Are you sure?",
          "message": "This action cannot be undone.",
          "variant": "danger"
        },
        "params": {
          "object": "project",
          "method": "delete",
          "id": "${record._id}"
        }
      },
      {
        "action": "toast.success",
        "params": { "message": "Project deleted successfully." }
      },
      {
        "action": "navigate",
        "params": { "url": "/projects" }
      }
    ]
  }
}

2. Standard Action Library

The ObjectUI Runtime comes with a built-in standard library of actions. You do not need to write code for these.

UI & Navigation

ActionParamsDescription
Mapsurl, targetGo to a URL or ObjectUI Route.
toast.successmessage, durationShow a green success notification.
toast.errormessageShow a red error notification.
modal.openlayout, titleOpen a JSON Layout in a dialog.
modal.close-Close the top-most dialog.
drawer.openlayout, widthOpen a slide-over panel.
copytextCopy text to clipboard.

Data & API

ActionParamsDescription
api.queryquery, bindRun an ObjectQL query and bind result to a variable.
api.mutationobject, method, dataExecute a create/update/delete.
form.submitformIdTrigger validation and submission of a specific form.
form.resetformIdReset form fields to default values.
record.refresh-Re-fetch the current record from the server.

3. Action Context & Variables

Actions run in a Context. You can access dynamic data using the ${variable} syntax.

  • ${record}: The current data record (row) being displayed.
  • ${user}: The current logged-in user session.
  • ${scope}: Temporary variables passed from parent components.
  • ${result}: The return value of the previous action in the chain.

Example: Using Previous Result

[
  // Step 1: Create a record
  {
    "action": "api.mutation",
    "params": { "object": "task", "method": "create", "data": {...} }
  },
  // Step 2: Navigate to the new ID
  {
    "action": "navigate",
    "params": { "url": "/tasks/${result.id}" }
  }
]

4. Client-Side Logic (action.script)

Sometimes standard actions aren't enough. You need custom calculation or logic. ObjectUI provides a Sandboxed Script Action.

Warning: This is not eval(). It is a safe, limited expression parser. It cannot access window, document, or making arbitrary network requests.

{
  "action": "script",
  "params": {
    "code": "if (record.amount > 1000) { return 'high_value'; } return 'standard';"
  },
  "output_to": "temp.category"
}

5. Action Containers

Often, actions are grouped into a generic "Toolbar" or "Menu".

Toolbar (layout.toolbar)

{
  "type": "layout.toolbar",
  "children": [
    {
      "type": "button",
      "props": { "label": "Edit", "icon": "edit" },
      "events": { "onClick": { "action": "modal.open", "params": { "layout": "edit_form" } } }
    },
    {
      "type": "button",
      "props": { "label": "More", "icon": "more_horizontal" },
      "children": [
        // Dropdown Menu Items
        { "label": "Duplicate", "action": "api.mutation", ... },
        { "label": "Archive", "action": "api.mutation", ... }
      ]
    }
  ]
}

6. Extending Actions

You can register custom actions in your frontend application code. This allows you to bridge the gap between the JSON Protocol and specific React capabilities.

// src/app.tsx
import { registerAction } from '@objectui/runtime';

registerAction('custom.printLabel', async (context, params) => {
  const zpl = generateZPL(context.record);
  await sendToBluetoothPrinter(zpl);
});

Usage in JSON:

{
  "action": "custom.printLabel",
  "params": { "format": "4x6" }
}

Summary

The Action Protocol turns imperative behavior into declarative configuration.

  1. Chaining: Actions execute sequentially.
  2. Context Aware: They can read the current record state.
  3. Safe: No raw JavaScript injection; only whitelisted actions.
  4. Confirmations: Built-in UI patterns for dangerous operations.

On this page