# Expressions

> Supported operators, control flow, builtin functions, and the $(...) variable syntax in Buttons expressions, with the errors you may see.

Buttons' expression editor understands a real JavaScript-like grammar (standard operators and precedence, if / for / while , arrow functions) plus a specific set of builtin functions and the $(...) variable-reference syntax. This page is a lookup reference for what's actually supported. For the v1.8 syntax changes if you're upgrading an existing system, see Update expressions for v1.8 . Operators Precedence follows standard JavaScript exactly: only which operators are allowed is restricted, not how they bind. Kind Operators Arithmetic / bitwise `+ - * / % ^ ** >> << & \ ( ^ is bitwise XOR here, not exponent: use `** for exponent) Comparison == != === !== > < >= <= Logical `\ \ && ??` (nullish coalescing) Unary - + ! ~ Update ++ -- (prefix or postfix) Assignment `= *= **= /= %= += -= <<= >>= &= ^= \ = \ \ = &&= ??=` Other Ternary ( a ? b : c ), comma/sequence ( a, b, c ), spread ( ...arr ), grouping + behaves like JavaScript's numeric addition first: it only falls back to string concatenation when the numeric result would be NaN , so '1' + '2' gives 3 , but 'a' + 1 gives 'a1' . Control flow and declarations: if / else , while , for , for...of (unlabelled break / continue only), return , let / const (not var ), and simple arrow functions ( (x) => x + 1 : no destructured parameters, not async ). Explicitly not supported: await , yield , this , tagged template literals, regex literals, BigInt literals, getters/setters, destructuring, optional calls ( fn?.() ), and method-style calls on a value ( a.b() ): only direct function calls are supported. Object literals: a {...} at the very start of an expression is read as an object literal, not a code block: for example, { 1: 'on', 2: 'off' }[$(internal:state)] is valid and works as a lookup table. Functions Math and numbers Function What it does round(v) / floor(v) / ceil(v) / abs(v) Standard rounding sqrt(v) / pow(base, exponent) Square root, exponentiation log(v, base?) / log10(v) / exp(v) Logarithm (natural, or given base) and exponential max(...) / min(...) Largest/smallest of the given values randomInt(min=0, max=10) Random inclusive integer fromRadix(str, radix=10) / toRadix(v, radix=10) Convert between a number and a string in a given base (2–36) toFixed(v, dp=0) Fixed decimal places (0–100) isNumber(v) True for a number, bigint, or a non-blank numeric string Strings Function What it does length(v) Length of a string (counting whole characters, not UTF-16 units), array, number, or object (key count) strlen(v) Raw string length in UTF-16 code units trim(v) Trims whitespace substr(str, start, end) / split(str, sep?) / join(arr, sep=',') Slice, split, and join concat(...) Concatenates strings includes(str, sub) / indexOf(str, sub, offset?) / lastIndexOf(str, sub, offset?) Search within a string toUpperCase(str) / toLowerCase(str) / replaceAll(str, find, replace) Case and replacement stringCompare(a, b) Locale-aware comparison, for use in a sort callback encode(str, enc) / decode(str, enc) Encode/decode using a Buffer encoding (default latin1 ) encodeURI(str) / decodeURI(str) / encodeURIComponent(str) / decodeURIComponent(str) Standard URI encoding Booleans Function What it does bool(v) Truthy, except the strings 'false' and '0' (case-insensitive) are false Objects, arrays, and JSON Function What it does jsonpath(obj, path) JSONPath query: auto-parses a JSON string input jsonparse(str) / jsonstringify(obj) Parse/stringify JSON, returning null on failure objectKeys(obj) / objectValues(obj) Like their JavaScript equivalents arrayIncludes / arrayIndexOf / arrayLastIndexOf Search within an array arrayMap / arrayFilter / arrayFind / arrayFindIndex / arraySome / arrayEvery / arrayForEach Standard iteration, each taking a callback function arrayReduce(arr, fn, initial) Reduce with an (accumulator, value, index) callback arraySort(arr, fn?) / arrayReverse(arr) / arraySlice(arr, start, end) Return a new, modified copy: the original array is untouched arrayConcat(...) / arrayFlat(arr) Combine arrays, or flatten one level Every function above that takes a callback throws "{name}() requires a function as its callback argument" if you pass something that isn't one: a common mistake worth checking first if one of these errors unexpectedly. Date and time Function What it does unixNow() Current time in milliseconds parseDate(v) Parses a date-like value to unix milliseconds, or null dateYear / dateMonth / dateDay / dateHour / dateMinute / dateSecond / dateWeekday (v, tz?) Individual date parts (weekday: 0 = Sunday) dateFormat(v, fmt='YYYY-MM-DDTHH:mm:ss', tz?) Formats using tokens like YYYY MM DD HH mm ss , or 'ISO' dateAdd(v, amount, unit) Adds a calendar amount ( unit = second/minute/hour/day/week/month/year), DST-safe timestampToSeconds(str) / secondsToTimestamp(v, format?) / msToTimestamp(v, format?) Convert between a HH:MM:SS -style timestamp and a numeric duration timeOffset(time, offset, hr12?) Adds an offset to a time-of-day string timeDiff(from, to) Seconds between two times Every date/time function accepts an optional IANA timezone name; without one, it uses your configured default time zone. Variable lookup Function What it does getVariable(name) / getVariable(label, name) Reads a variable's current value dynamically: this is the only supported way to look up a variable by a computed name; the older getVariableValue alias was removed in v1.8 parseVariables(str, undefinedValue?) Substitutes every $(...) reference found inside a string and returns the resolved result: this is also how you get inside-out nested-reference resolution inside an expression , since $(...) itself doesn't nest as a literal token (see Understand nested variables ) Clock-driven functions Function What it does blink(interval, dutyCycle=0.5) Returns 1/0, toggling on a repeating interval (minimum 100ms) oscillate(period, waveform='sine', phase=0) Returns a continuous 0–1 value cycling over a period; waveform is sine , triangle , sawtooth , or square Note blink , oscillate , and parseVariables only work where Buttons can supply a live clock/variable context: on a button, feedback, or similar continuously-evaluated field. They throw "{name} is not supported here" inside a Workflow Expression node, which evaluates once and has no ongoing context to re-run against. Constant PI is available as a bare identifier ( Math.PI ), not a function call. The $(...) variable reference Inside $(...) , use letters, digits, _ , - , : , and . to identify a variable: Buttons reads this as a dot-joined path (for example ns.a ). The reference is read as one opaque token up to its first ) ; it does not parse a literal nested $(...) inside it. See Understand nested variables for the two mechanisms that do support nesting in practice. Errors you might see while authoring an expression Message What it means Unsupported function "{name}" The function name doesn't exist: check spelling, and remember getVariableValue was removed in v1.8 (use getVariable ). {name}() requires a function as its callback argument An array function like arrayMap was called without a real callback function. {name} is not supported here You called blink , oscillate , or parseVariables somewhere without a live clock/variable context, such as a Workflow Expression node. Unsupported syntax "{type}" / Unsupported binary/logical/assignment operator "{op}" The expression uses a construct or operator that isn't on the supported list. Only direct function calls are supported You tried to call a method on a value ( a.b() ) rather than calling a plain function. Access to property "{property}" is not allowed The expression touched a banned property name ( __proto__ , constructor , prototype , and similar). Expression evaluation exceeded the maximum number of operations / ...maximum call depth The expression is too large or recurses too deeply to safely evaluate: simplify it. If you get stuck What you see What to try A function you expect to exist throws "Unsupported function." Double check the exact name against this page: a similar-sounding function elsewhere in JavaScript may not exist here. blink / oscillate / parseVariables throws "not supported here." You're likely inside a Workflow Expression node: these only work in continuously-evaluated contexts like a button or feedback. A $(something_$(something_else)) -style nested reference doesn't resolve as expected inside an expression. Use parseVariables(...) instead: the $(...) token itself doesn't parse a literal nested reference. An array function throws about needing a callback. Confirm you're actually passing a function, not a value, as that argument. Where to go next Update expressions for v1.8 Understand nested variables Use variables in controls and expressions
