⌘K

Action

Actions in the Nativeblocks DSL. Attaching triggers to block events, chaining, the built-in script action, and imports.

Actions (also called triggers) run when a block fires an event: a tap, a text change, a form submission, or any custom event the block defines. You attach them to a block's event slots. Multiple actions in the same slot run in declaration order.

There are two kinds:

  • Registered actions are custom logic generated from an installed integration. See Block & Action for how to build them.
  • script is a built-in inline action for reading and writing variables and updating block properties without a separate integration.

Unlike blocks, actions have no slots and no visibility. Properties take a single value (no breakpoints), data binds a variable, and the only events are onNext, onSuccess, and onFailure, each chaining the next trigger.


Action factory

Registered actions are factory functions. Everything is a named argument: actionName, properties, data, and the chaining events.

analyticsAction(
    actionName = "track",
    route = "value",          // property
    payload = dataVar,        // data
    onNext = {                // chain the next trigger
        navigateAction(actionName = "nav")
    },
)
ParameterTypeDescription
actionName (name in TypeScript)stringUnique name for this action within the frame. Auto-generated if omitted.

Properties

Action properties take a single value with no breakpoints.

analyticsAction(actionName = "track", route = "value")

Data

Data binds a frame variable. The action reads the variable's current value at runtime.

Data is a named argument whose name is the data key.

navigateAction(actionName = "nav", payload = routeVar)

Events

Actions support three chaining events. Only these three are valid:

EventWhen it runs
onNextAfter this action completes, regardless of outcome
onSuccessOnly when this action succeeds
onFailureOnly when this action fails

Registered actions take chaining events as named-argument lambdas. The built-in script chains .onNext { }.

requestAction(
    actionName = "request",
    onSuccess = { showSuccessAction(actionName = "ok") },
    onFailure = { showErrorAction(actionName = "err") },
)

script { _, updateVariable, _ ->
    updateVariable(stepVar, "1")
}.onNext {
    script { _, updateVariable, _ ->
        updateVariable(stepVar, "2")
    }
}

Attaching to blocks

Attach one or more actions to a block event. They run top to bottom.

nativeblocksButton(
    blockKey = "btn",
    onClick = {
        navigateAction(actionName = "nav")
        script { _, updateVariable, _ ->
            updateVariable(loadingVar, "true")
        }
    },
)

Rules

  • Actions do not return values. Communicate results by writing to frame variables.
  • Actions inside the same event run in declaration order.
  • Use onNext / onSuccess / onFailure to chain actions that must run sequentially across async boundaries.
  • Avoid long-running or blocking work inside script.
  • Every action name must be unique within a frame.

script

script is the built-in action for inline logic. The build closure receives three helper functions:

FunctionWhat it does
getVariable(variable)Produces the getVariable("key") read expression. The runtime returns the value as a string.
updateVariable(variable, value)Produces an updateVariable("key", …) write. value is a template string, embed another variable to splice in its live value.
updateBlockProperties(key, property, values)Updates a block's visual property at runtime without rebuilding the frame.

The script body is JavaScript at runtime.

The build closure returns the JavaScript body string. Helper calls produce snippet strings; for computed writes, write JavaScript directly (v.key gives the variable's key).

// Single templated write: return the snippet directly
script { _, updateVariable, _ ->
    updateVariable(myVar, "newValue")
}

// Reference another variable's live value with {{var:key}}
script { _, updateVariable, _ ->
    updateVariable(greeting, "Hello {{var:userName}}")
}

// Read then compute: splice the read expression, write raw JavaScript
script { getVariable, _, _ ->
    """
    let n = Number(${getVariable(myVar)});
    updateVariable("${myVar.key}", String(n + 1));
    """.trimIndent()
}

Optional name: script(name = "myScript") { ... }.

updateBlockProperties

The third argument is the property value per breakpoint. Pass only the breakpoints you want to change; omitted ones keep their current value. The key must match a block's blockKey in the same frame.

// Single breakpoint
updateBlockProperties("card", "backgroundColor", BlockPropValues(mobile = "#FF0000"))

// Multiple breakpoints
updateBlockProperties("card", "backgroundColor", BlockPropValues(
    mobile = "#FF0000",
    tablet = "#00FF00",
    desktop = "#0000FF",
))

Common patterns

Boolean toggle

script { getVariable, _, _ ->
    """updateVariable("${flagVar.key}", String(${getVariable(flagVar)} !== "true"));"""
}

INDEX: current item in a repeating block

INDEX gives the current iteration index when a script runs inside a repeating block. It compiles to the {{index}} placeholder.

script { getVariable, _, _ ->
    "let item = JSON.parse(${getVariable(listVar)})[$INDEX];"
}

Helper functions

When the same action sequence repeats, extract it into a helper declared outside the frame function.

Helpers must extend ActionsScope so action factory calls self-register:

fun ActionsScope.trackAndNavigate(routeVar: Variable) {
    analyticsAction(actionName = "track", route = routeVar.value)
    navigateAction(actionName = "nav", payload = routeVar)
}

fun frame(): NativeblocksFrame = androidFrame(name = "Home", route = "/home") {
    rootBlock {
        nativeblocksButton(blockKey = "btn", onClick = {
            trackAndNavigate(routeVar)
        })
    }
}

Imports

import com.example.app.generated.integration.android.Script.script
import com.example.app.generated.integration.android.nativeblocks.navigate.navigateAction

script and INDEX live in the platform Script package; registered actions follow the same path pattern as blocks.