Skip to main content
Expressions resolve identifiers from a context object. What’s in that context depends on where the expression runs — global state is always available, but components like State and ForEach can layer on additional scoped values.

Global State

Global state is always accessible from any expression. Values enter global state from three sources: AppResult — the initial state set by your server code:
from prefab_ui import AppResult

AppResult(state={"count": 0, "name": "Arthur"}, view=...)
Named form controls — any component with a name prop syncs its current value to state automatically. Input(name="city") updates {{ city }} on every keystroke. ActionsSetState and ToolCall (via result_key) write to global state when they fire.

Local Scope

The State component provides scoped values to its children. These shadow global state within the subtree — inner values win over outer ones for the same key. The first Text renders “Don’t Panic, Arthur”. The second renders “Don’t Panic, Ford” — the inner State shadows name but inherits greeting from the outer scope.

Dot Paths

Use dot notation to reach into nested objects:
{{ user.address.city }}
{{ order.items.length }}
.length works on both arrays and strings. If any segment of the path is null or undefined, the entire expression resolves to undefined.

Special Variables

Several variables are injected automatically by the framework in specific contexts.

$event

Available inside action specs. Contains the value from the triggering interaction — what that means depends on the component:
Component$event value
Input / TextareaCurrent text (string)
SliderCurrent position (number)
Checkbox / SwitchChecked state (boolean)
SelectSelected value (string)
RadioGroupSelected value (string)
Buttonundefined
SetState defaults to "{{ $event }}" when no explicit value is provided, which is why SetState("volume") on a slider captures the slider position.

$error

Available inside on_error callbacks. Contains the error message string from the failed action.
from prefab_ui import ToolCall, ShowToast

Button("Save", on_click=ToolCall(
    "save_data",
    on_error=ShowToast("Failed: {{ $error }}", variant="error"),
))

$index

Available inside ForEach iterations. The zero-based index of the current item.
from prefab_ui.components import ForEach, Text

with ForEach("items"):
    Text("{{ $index + 1 }}. {{ name }}")
    # Renders: "1. First", "2. Second", etc.
$index is how actions target specific list items from inside a loop — SetState("todos.{{ $index }}.done") updates the done field of the item at the current position.

$item

Available inside ForEach iterations. A reference to the entire current item object. Individual fields are also available directly ({{ name }} instead of {{ $item.name }}), but $item is useful when you need to pass the whole object to an action:
from prefab_ui.components import ForEach, Button, Text
from prefab_ui import ToolCall

with ForEach("users"):
    Text("{{ name }}")
    Button("Edit", on_click=ToolCall(
        "edit_user",
        arguments={"user": "{{ $item }}"},
    ))

Conditional Rendering

If/Elif/Else blocks use expressions to control which components render. The expression evaluates to a truthy or falsy value, and the first matching branch renders. This is one of the most practical uses of expression context — combining state from different sources to determine what the user sees: Drag the slider to zero to see the “Out of stock!” alert appear. Values between 1 and 9 show the “Low stock warning” instead.