{{ }} interpolation and the assign action). Each is deliberately limited. This page documents exactly what is supported so you do not write something the runtime silently drops.
Conditions
ACondition is a pure, read-only test against a variable. It never mutates state and must be deterministic. Conditions read variables only, through a VarRef:
left (a VarRef) and, for most operators, a right literal.
Operators by type
The empty-check operators (
is_empty, is_not_empty) take no right operand.
is_full — a list’s selection limit
is_full is true when a List variable has reached the Selection limit
(maxSelections) declared on the variable itself. It takes no right operand:
the limit is never repeated in the condition, so re-capping a question is a
one-number edit on the variable and the conditions can’t drift out of sync
with it.
A list with no limit is never full, so is_full is inert — always false —
until a limit is declared. It is false for every non-list type.
This is what greys out the remaining answers of a capped multi-select question.
The editor compiles this onto each option automatically when you set a
Max selections — you rarely write it by hand:
Logical operators
Compose conditions with:Shape examples
Evaluation notes
- A type mismatch fails the comparison rather than throwing. A numeric operator on a non-number returns
false. Astarts_with/ends_with/containson a non-string returnsfalse(fornot_contains, an absent/non-string value returnstrue). - A missing variable is treated as empty:
is_emptyistrue,is_not_emptyisfalse. - An unknown operator fails safely to
false. - The dashboard renderer (
variable-runtime.ts) and both SDKs (each ships aConditionEvaluator, kept in lockstep) implement the same operator set.
Property values
Component props can be a plain value or aPropertyValue<T>:
static: return the value directly.conditional: evaluatecasesin order. The first case whosewhencondition is true wins.- If no case matches, fall back to
else. - If nothing matches and there is no
else, the result is undefined (the renderer uses its own default).
ConditionalCase<T> is { when: Condition; value: PropertyValue<T>; label?: string }. Case values can themselves be conditional, so they nest.
Example: a color that depends on a variable.
Interpolation: {{ }}
String props support {{variableName}} interpolation. The braces are replaced with the variable’s current value, converted to a string.
- Only the variable’s value is substituted. The braces hold a bare variable name, nothing else.
- A missing variable resolves to an empty string.
- Interpolation re-runs when the variable changes.
PropertyValue (shown above), not an expression inside {{ }}.
Expressions (the assign subset)
The assign action and node use a FlowExpression: a string in a small “JS-like” safe subset. The SDKs’ ExpressionEvaluator (the iOS and Expo implementations are kept in lockstep) defines the supported contract:
Supported
- Literals:
true,false,null, numbers (decimal, negative, leading dot), and quoted strings ("..."or'...'). - Variable references: a bare identifier (
userName) or avars.prefix (vars.userName). - A single binary arithmetic operator (
+,-,*,/,%) when both operands resolve to numbers. - String concatenation with
+when either operand resolves to a string (the other operand is coerced).
- Parentheses.
- Comparison operators (
>,<,==, and so on). Use a condition for comparisons. - Function calls.
- Multi-operator chains (for example
a + b + c). Only one top-level operator is parsed.
setVariable action when you need comparisons or branching, since expressions cannot compare.