---
title: Action Protocol
description: Buttons, triggers, navigation, and user interaction definitions
---

import { MousePointer, Zap, ExternalLink, Workflow, GitBranch, Play, Component, Layout } from 'lucide-react';


The **Action Protocol** specifies how user interactions (button clicks, menu selections, gestures) trigger business logic, navigation, or external integrations. Actions are the "verbs" of ObjectUI—they make things happen.

## Philosophy: Declarative Interactions

Instead of writing `onClick` handlers in JavaScript, you declare what should happen in metadata:

```yaml
# ❌ Imperative (React)
<Button onClick={() => {
  if (validate()) {
    api.post('/customers', data);
    router.push('/customers');
  }
}}>Save</Button>

# ✅ Declarative (ObjectUI)
action:
  type: standard_save
  label: Save
  onSuccess:
    - navigate: /customers
```

**Benefits:**
- **No code:** Business analysts configure actions
- **Type-safe:** Actions validated against schema
- **Testable:** Actions are data, can be unit tested
- **Auditable:** See what actions users can perform

## Action Types

ObjectUI defines several categories of actions.

### Standard Actions

Built-in CRUD operations that require no configuration:

```yaml
actions:
  - type: standard_new
    label: New Customer
    object: customer
  
  - type: standard_edit
    label: Edit
    recordId: '{recordId}'
  
  - type: standard_delete
    label: Delete
    recordId: '{recordId}'
    confirm: true  # Show confirmation dialog
  
  - type: standard_save
    label: Save
    validate: true  # Run validation before saving
  
  - type: standard_cancel
    label: Cancel
    confirmIfDirty: true  # Warn if unsaved changes
```

**Standard Actions Available:**
- `standard_new` - Create new record
- `standard_edit` - Edit existing record
- `standard_delete` - Delete record
- `standard_save` - Save current form
- `standard_cancel` - Cancel and return
- `standard_clone` - Clone record
- `standard_refresh` - Reload data
- `standard_export` - Export to CSV/Excel
- `standard_print` - Print view

### Navigation Actions

Navigate to different pages or external URLs:

```yaml
actions:
  - type: navigate
    label: View Dashboard
    target: /dashboards/sales_overview
  
  - type: navigate
    label: View Customer
    target: /customers/{customer_id}  # Dynamic parameter
  
  - type: navigate
    label: External Link
    target: https://example.com
    openInNewTab: true
  
  - type: navigate_back
    label: Go Back
    fallback: /customers  # If no history, go here
```

### Flow Actions

Launch Screen Flows (multi-step wizards):

```yaml
actions:
  - type: flow
    label: Approve Request
    flow: approval_wizard
    input:
      recordId: '{recordId}'
      approver: '{currentUserId}'
    onComplete:
      - action: refresh
      - action: toast
        message: Request approved successfully
```

### API Actions

Call custom REST endpoints:

```yaml
actions:
  - type: api
    label: Sync with ERP
    method: POST
    endpoint: /api/integrations/erp/sync
    params:
      customerId: '{recordId}'
    headers:
      X-Custom-Header: value
    onSuccess:
      - action: toast
        message: Sync completed successfully
        variant: success
    onError:
      - action: toast
        message: Sync failed: {error}
        variant: error
```

### Workflow Actions

Trigger server-side workflows:

```yaml
actions:
  - type: workflow
    label: Send Reminder
    workflow: send_customer_reminder
    input:
      customerId: '{recordId}'
      reminderType: payment_due
    async: true  # Don't wait for completion
```

### Modal Actions

Open modals (dialogs) with embedded content:

```yaml
actions:
  - type: modal
    label: Quick Edit
    title: Edit Customer
    content:
      type: form
      object: customer
      recordId: '{recordId}'
      fields: [name, email, phone]
    size: medium
    actions:
      - type: standard_save
        label: Save
        closeOnSuccess: true
      - type: standard_cancel
        label: Cancel
```

### Bulk Actions

Operate on multiple selected records:

```yaml
# In ListView
actions:
  - type: bulk_update
    label: Update Status
    availableWhen: rowsSelected
    fields:
      - name: status
        type: select
        options: [active, inactive, pending]
    onSuccess:
      - action: refresh
  
  - type: bulk_delete
    label: Delete Selected
    availableWhen: rowsSelected
    confirm:
      title: Delete {count} records?
      message: This action cannot be undone
      confirmLabel: Delete
      cancelLabel: Cancel
```

### Custom Actions

Execute custom JavaScript (renderer-side):

```yaml
actions:
  - type: custom
    label: Calculate Discount
    handler: calculateDiscount  # Function registered in renderer
    params:
      quantity: '{quantity}'
      unitPrice: '{unit_price}'
```

## Action Configuration

### Basic Action Properties

```typescript
interface Action {
  // Identification
  type: ActionType;
  name?: string;                // Unique name
  label: string;                // Button text
  
  // Display
  icon?: string;                // Lucide icon
  variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
  size?: 'small' | 'medium' | 'large';
  
  // Visibility & State
  visible?: VisibilityRule;     // When to show
  disabled?: DisabledRule;      // When to disable
  availableWhen?: Condition;    // Conditional availability
  
  // Confirmation
  confirm?: boolean | ConfirmDialog;
  
  // Execution
  onBefore?: Action[];          // Run before main action
  onSuccess?: Action[];         // Run on success
  onError?: Action[];           // Run on error
  onFinally?: Action[];         // Run always (cleanup)
}
```

### Visibility Rules

Control when actions appear:

```yaml
actions:
  # Show only if status is 'draft'
  - type: standard_edit
    label: Edit
    visible:
      field: status
      value: draft
  
  # Show only if user has permission
  - type: standard_delete
    label: Delete
    visible:
      permission: delete_customers
  
  # Show based on multiple conditions
  - type: workflow
    label: Approve
    visible:
      and:
        - { field: status, value: pending }
        - { permission: approve_requests }
        - { field: amount, operator: '<', value: 10000 }
```

### Disabled Rules

Disable actions based on conditions:

```yaml
actions:
  # Disable if form is invalid
  - type: standard_save
    label: Save
    disabled:
      formInvalid: true
  
  # Disable if record has children
  - type: standard_delete
    label: Delete
    disabled:
      field: has_open_orders
      value: true
    disabledTooltip: Cannot delete customer with open orders
  
  # Disable based on field value
  - type: workflow
    label: Ship Order
    disabled:
      or:
        - { field: status, operator: '!=', value: paid }
        - { field: inventory_available, value: false }
```

## Confirmation Dialogs

Show confirmation before destructive actions.

### Simple Confirmation

```yaml
action:
  type: standard_delete
  label: Delete Customer
  confirm: true  # Default confirmation
```

**Renders:**
```
┌─────────────────────────────────┐
│ Confirm Delete                  │
├─────────────────────────────────┤
│ Are you sure you want to        │
│ delete this customer?           │
│                                 │
│       [Cancel]  [Delete]        │
└─────────────────────────────────┘
```

### Custom Confirmation

```yaml
action:
  type: bulk_delete
  label: Delete Selected
  confirm:
    title: Delete {count} customers?
    message: |
      This will permanently delete {count} customers
      and all related records. This action cannot
      be undone.
    icon: alert-triangle
    variant: danger
    confirmLabel: Yes, Delete
    cancelLabel: Cancel
    requireTyping: DELETE  # User must type "DELETE" to confirm
```

## Parameter Binding

Actions can reference form data and context variables.

### Variable Syntax

```yaml
action:
  type: api
  endpoint: /api/customers/{customer_id}/send-email
  params:
    # Field values
    email: '{email}'
    name: '{name}'
    
    # System variables
    currentUser: '{$userId}'
    timestamp: '{$now}'
    
    # Computed values
    fullName: '{first_name} {last_name}'
    
    # Nested fields
    billingCity: '{billing_address.city}'
```

### Available Variables

```typescript
// Form field values
{fieldName}                     // e.g., {customer_name}

// System variables
{$userId}                       // Current user ID
{$userName}                     // Current user name
{$userEmail}                    // Current user email
{$now}                          // Current timestamp
{$recordId}                     // Current record ID
{$objectName}                   // Current object name

// Context variables (ListView)
{$selectedRows}                 // Selected row IDs
{$selectedCount}                // Count of selected rows
{$filteredCount}                // Count after filters

// Context variables (FormView)
{$isNew}                        // True if creating new record
{$isEditing}                    // True if editing existing
{$isDirty}                      // True if form has unsaved changes
{$isValid}                      // True if form passes validation
```

## Action Chains

Execute multiple actions in sequence or parallel.

### Sequential Actions

```yaml
action:
  type: standard_save
  label: Save & Send Email
  onSuccess:
    - action: api
      type: api
      endpoint: /api/send-welcome-email
      params:
        customerId: '{recordId}'
    
    - action: navigate
      type: navigate
      target: /customers/{recordId}
    
    - action: toast
      type: toast
      message: Customer saved and email sent
      variant: success
```

### Parallel Actions

```yaml
action:
  type: standard_save
  label: Save
  onSuccess:
    parallel: true  # Execute in parallel
    actions:
      - type: api
        endpoint: /api/analytics/track
        params:
          event: customer_created
      
      - type: api
        endpoint: /api/crm/sync
        params:
          recordId: '{recordId}'
      
      - type: workflow
        workflow: send_notifications
        input:
          recordId: '{recordId}'
```

### Conditional Chains

```yaml
action:
  type: standard_save
  label: Save
  onSuccess:
    - when: { field: send_email, value: true }
      action:
        type: api
        endpoint: /api/send-email
    
    - when: { field: amount, operator: '>', value: 10000 }
      action:
        type: workflow
        workflow: high_value_alert
```

## Action Placement

Actions can appear in different UI locations.

### Form Actions

Buttons in form header or footer:

```yaml
form:
  object: customer
  actions:
    placement: footer  # or 'header' | 'both'
    align: right       # or 'left' | 'center' | 'space-between'
    actions:
      - type: standard_save
        label: Save
        variant: primary
      - type: standard_cancel
        label: Cancel
        variant: secondary
```

### Row Actions

Actions in list view rows:

```yaml
listView:
  object: customer
  rowActions:
    - type: standard_edit
      label: Edit
      icon: edit
    
    - type: standard_delete
      label: Delete
      icon: trash
      confirm: true
    
    - type: separator  # Visual separator
    
    - type: api
      label: Send Email
      icon: mail
      endpoint: /api/customers/{id}/send-email
```

### Dropdown Menu Actions

Group actions in a dropdown:

```yaml
actions:
  - type: menu
    label: More Actions
    icon: more-vertical
    items:
      - type: standard_clone
        label: Clone Customer
      - type: api
        label: Export to PDF
        endpoint: /api/customers/{id}/export-pdf
      - type: separator
      - type: workflow
        label: Merge Duplicate
        workflow: merge_customers
```

### Bulk Actions (List View)

Actions that operate on selected rows:

```yaml
listView:
  object: customer
  bulkActions:
    - type: bulk_update
      label: Change Status
      icon: edit
      fields:
        - name: status
          type: select
          options: [active, inactive]
    
    - type: bulk_delete
      label: Delete
      icon: trash
      confirm: true
```

### Quick Actions (Record Page)

Floating action buttons:

```yaml
page:
  object: customer
  quickActions:
    - type: api
      label: Call Customer
      icon: phone
      endpoint: /api/telephony/call
      params:
        phone: '{phone}'
    
    - type: navigate
      label: View Map
      icon: map
      target: https://maps.google.com?q={address}
      openInNewTab: true
```

## Navigation Patterns

### Internal Navigation

```yaml
# Navigate to object list
action:
  type: navigate
  target: /customers

# Navigate to specific record
action:
  type: navigate
  target: /customers/{customer_id}

# Navigate to related record
action:
  type: navigate
  target: /accounts/{account_id}
  params:
    recordId: '{account_id}'

# Navigate to dashboard
action:
  type: navigate
  target: /dashboards/sales_overview
```

### External Navigation

```yaml
# Open external URL
action:
  type: navigate
  label: View Website
  target: https://{website}
  openInNewTab: true

# Deep link to external app
action:
  type: navigate
  label: Open in Slack
  target: slack://channel?id={slack_channel_id}

# Email link
action:
  type: navigate
  label: Send Email
  target: mailto:{email}?subject=Hello&body=Message
```

### Contextual Navigation

```yaml
# Navigate with state
action:
  type: navigate
  target: /orders/new
  state:
    customerId: '{customer_id}'
    prefillData:
      shipping_address: '{address}'

# Navigate and replace history
action:
  type: navigate
  target: /customers
  replace: true  # Don't add to history stack
```

## Integration Actions

### Webhook Actions

Trigger external webhooks:

```yaml
action:
  type: webhook
  label: Notify Slack
  url: https://hooks.slack.com/services/XXX/YYY/ZZZ
  method: POST
  headers:
    Content-Type: application/json
  body:
    text: "New customer: {name}"
    channel: "#sales"
```

### OAuth Actions

Initiate OAuth flows:

```yaml
action:
  type: oauth
  label: Connect Google Calendar
  provider: google
  scopes:
    - https://www.googleapis.com/auth/calendar
  onSuccess:
    - action: toast
      message: Google Calendar connected
```

### File Upload Actions

Upload files to external storage:

```yaml
action:
  type: file_upload
  label: Upload Attachment
  accept: .pdf,.docx,.xlsx
  maxSize: 10485760  # 10MB
  storage: s3
  bucket: customer-documents
  path: customers/{customer_id}/
  onSuccess:
    - action: update_field
      field: attachment_url
      value: '{uploadedUrl}'
```

## State Management Actions

### Update Field Values

```yaml
action:
  type: update_field
  field: total_price
  value: '{quantity} * {unit_price}'

# Multiple fields
action:
  type: update_fields
  fields:
    status: completed
    completed_at: '{$now}'
    completed_by: '{$userId}'
```

### Clear Fields

```yaml
action:
  type: clear_fields
  fields: [shipping_address, shipping_method]

# Clear with condition
action:
  type: clear_fields
  when: { field: shipping_required, value: false }
  fields: [shipping_address]
```

### Show/Hide Fields

```yaml
action:
  type: show_fields
  fields: [billing_address, payment_method]

action:
  type: hide_fields
  fields: [internal_notes, api_key]
```

### Toggle Sections

```yaml
action:
  type: toggle_section
  section: advanced_settings
```

## Feedback Actions

### Toast Notifications

```yaml
action:
  type: toast
  message: Customer saved successfully
  variant: success  # or 'error' | 'warning' | 'info'
  duration: 3000    # milliseconds
  position: top-right

# With action button
action:
  type: toast
  message: Draft saved
  variant: info
  action:
    label: View
    onClick:
      type: navigate
      target: /customers/{recordId}
```

### Alert Dialogs

```yaml
action:
  type: alert
  title: Error
  message: Failed to save customer
  variant: error
  buttons:
    - label: Retry
      action:
        type: standard_save
    - label: Cancel
```

### Progress Indicators

```yaml
action:
  type: api
  label: Generate Report
  endpoint: /api/reports/generate
  showProgress: true
  progressMessage: Generating report...
  onProgress:
    - action: update_progress
      percent: '{progress}'
```

## Real-World Examples

### Approve/Reject Workflow

```yaml
actions:
  - type: workflow
    label: Approve
    icon: check-circle
    variant: primary
    workflow: approval_flow
    input:
      recordId: '{recordId}'
      decision: approved
      comments: '{approval_comments}'
    confirm:
      title: Approve this request?
      message: This will notify the requestor
    onSuccess:
      - action: toast
        message: Request approved
        variant: success
      - action: navigate
        target: /requests
  
  - type: workflow
    label: Reject
    icon: x-circle
    variant: danger
    workflow: approval_flow
    input:
      recordId: '{recordId}'
      decision: rejected
      comments: '{rejection_reason}'
    confirm:
      title: Reject this request?
      message: Please provide a reason in the comments
      requireField: rejection_reason
    onSuccess:
      - action: toast
        message: Request rejected
        variant: warning
      - action: navigate
        target: /requests
```

### Send Email with Template

```yaml
action:
  type: modal
  label: Send Email
  icon: mail
  title: Send Email to Customer
  content:
    type: form
    fields:
      - name: template
        type: select
        label: Email Template
        options:
          - { value: welcome, label: Welcome Email }
          - { value: invoice, label: Invoice Email }
          - { value: reminder, label: Payment Reminder }
      - name: subject
        type: text
        label: Subject
        value: '{template.subject}'
      - name: body
        type: richtext
        label: Message
        value: '{template.body}'
  actions:
    - type: api
      label: Send
      variant: primary
      endpoint: /api/emails/send
      method: POST
      params:
        to: '{email}'
        subject: '{subject}'
        body: '{body}'
        customerId: '{recordId}'
      onSuccess:
        - action: toast
          message: Email sent successfully
        - action: close_modal
    - type: standard_cancel
      label: Cancel
```

### Multi-Step Data Migration

```yaml
action:
  type: flow
  label: Migrate Data
  icon: database
  flow: data_migration_wizard
  steps:
    - name: select_source
      title: Select Source
      fields:
        - source_type
        - connection_string
    
    - name: field_mapping
      title: Map Fields
      component: field_mapper
      props:
        sourceFields: '{sourceFields}'
        targetObject: customer
    
    - name: validation
      title: Validate Data
      component: migration_validator
      props:
        mapping: '{fieldMapping}'
    
    - name: execute
      title: Execute Migration
      component: migration_progress
      onExecute:
        type: api
        endpoint: /api/migrations/execute
        method: POST
        params:
          mapping: '{fieldMapping}'
        async: true
  onComplete:
    - action: navigate
      target: /migrations/{migrationId}
```

### Export with Options

```yaml
action:
  type: modal
  label: Export
  icon: download
  title: Export Customers
  content:
    type: form
    fields:
      - name: format
        type: select
        label: Format
        options: [CSV, Excel, PDF]
        default: CSV
      - name: includeFields
        type: multiselect
        label: Fields to Include
        options: [name, email, phone, address, status]
      - name: filterBy
        type: select
        label: Filter
        options:
          - { value: all, label: All Customers }
          - { value: active, label: Active Only }
          - { value: selected, label: Selected Rows Only }
  actions:
    - type: api
      label: Export
      variant: primary
      endpoint: /api/customers/export
      method: POST
      params:
        format: '{format}'
        fields: '{includeFields}'
        filter: '{filterBy}'
        selectedIds: '{$selectedRows}'
      onSuccess:
        - action: download
          url: '{exportUrl}'
        - action: toast
          message: Export started. Download will begin shortly.
        - action: close_modal
```

## Action Schema Reference

```typescript
interface Action {
  // Core
  type: ActionType;
  name?: string;
  label: string;
  
  // Display
  icon?: string;
  variant?: 'primary' | 'secondary' | 'danger' | 'ghost' | 'link';
  size?: 'small' | 'medium' | 'large';
  fullWidth?: boolean;
  
  // State
  visible?: VisibilityRule;
  disabled?: DisabledRule;
  loading?: boolean;
  
  // Execution
  confirm?: boolean | ConfirmConfig;
  async?: boolean;
  debounce?: number;
  
  // Callbacks
  onBefore?: Action[];
  onSuccess?: Action[];
  onError?: Action[];
  onFinally?: Action[];
  
  // Type-specific props
  [key: string]: any;
}

type ActionType =
  | 'standard_new' | 'standard_edit' | 'standard_delete'
  | 'standard_save' | 'standard_cancel' | 'standard_clone'
  | 'navigate' | 'navigate_back'
  | 'flow' | 'api' | 'workflow'
  | 'modal' | 'toast' | 'alert'
  | 'bulk_update' | 'bulk_delete'
  | 'update_field' | 'clear_fields' | 'show_fields' | 'hide_fields'
  | 'webhook' | 'oauth' | 'file_upload'
  | 'custom';
```

## What's Next?

<Cards>
  <Card
    icon={<Layout />}
    title="Layout DSL"
    href="/docs/protocols/objectui/layout-dsl"
    description="Learn how to structure pages and sections"
  />
  <Card
    icon={<Component />}
    title="Widget Contract"
    href="/docs/protocols/objectui/widget-contract"
    description="Understand component props and events"
  />
</Cards>

## Related Resources

- [FormView Actions](/docs/references/ui/FormView#actions) - Form-specific actions
- [ListView Actions](/docs/references/ui/ListView#actions) - List view actions
- [Flow Builder](/docs/guides/flow-builder) - Build multi-step flows
- [Workflow Engine](/docs/protocols/objectos/workflows) - Server-side automation
