Expressions

Complete reference for all expression types in Constela

Overview

Expressions are the way to work with dynamic values in Constela. They can represent literal values, state access, variable access, and computed values.

Literal Expression

Represents a static, constant value.

json
{ "expr": "lit", "value": "Hello, World!" }
{ "expr": "lit", "value": 42 }
{ "expr": "lit", "value": true }
{ "expr": "lit", "value": ["a", "b", "c"] }
NameTypeRequiredDefaultDescription
expr"lit"Yes-Expression type identifier.
valueanyYes-The literal value (string, number, boolean, array, or object).

State Expression

Accesses a value from the application state.

json
{ "expr": "state", "name": "count" }
{ "expr": "state", "name": "user" }
NameTypeRequiredDefaultDescription
expr"state"Yes-Expression type identifier.
namestringYes-Name of the state field to access.

Nested Property Access

Use the get expression to access properties within state objects:

json
// Access state.user.profile.name
{
  "expr": "get",
  "base": { "expr": "state", "name": "user" },
  "path": "profile.name"
}

// Access state.settings.theme
{
  "expr": "get",
  "base": { "expr": "state", "name": "settings" },
  "path": "theme"
}

Variable Expression

Accesses a loop variable or component prop.

json
{ "expr": "var", "name": "item" }
{ "expr": "var", "name": "user", "path": "email" }
NameTypeRequiredDefaultDescription
expr"var"Yes-Expression type identifier.
namestringYes-Name of the variable (from each loop's 'as' or component props).
pathstringNo-Dot-notation path for nested property access.

Usage in Each Loop

json
{
  "kind": "each",
  "items": { "expr": "state", "name": "users" },
  "as": "user",
  "index": "i",
  "body": {
    "kind": "text",
    "value": { "expr": "var", "name": "user", "path": "name" }
  }
}

Binary Expression

Computes a value from two operands and an operator.

json
{
  "expr": "bin",
  "op": "+",
  "left": { "expr": "state", "name": "count" },
  "right": { "expr": "lit", "value": 1 }
}
NameTypeRequiredDefaultDescription
expr"bin"Yes-Expression type identifier.
opstringYes-Binary operator (see operators table below).
leftExpressionYes-Left operand expression.
rightExpressionYes-Right operand expression.

Binary Operators

OperatorDescriptionExample
+Addition / String concatenation5 + 3 = 8, "a" + "b" = "ab"
-Subtraction5 - 3 = 2
*Multiplication5 * 3 = 15
/Division6 / 3 = 2
==Equality5 == 5 is true
!=Inequality5 != 3 is true
<Less than3 < 5 is true
<=Less than or equal3 <= 3 is true
>Greater than5 > 3 is true
>=Greater than or equal5 >= 5 is true
&&Logical ANDtrue && false is false
||Logical ORtrue || false is true

Complex Expression Example

json
{
  "expr": "bin",
  "op": "&&",
  "left": {
    "expr": "bin",
    "op": ">",
    "left": { "expr": "state", "name": "count" },
    "right": { "expr": "lit", "value": 0 }
  },
  "right": {
    "expr": "bin",
    "op": "<",
    "left": { "expr": "state", "name": "count" },
    "right": { "expr": "lit", "value": 100 }
  }
}

This evaluates to true when count > 0 && count < 100.

Not Expression

Negates a boolean expression.

json
{
  "expr": "not",
  "operand": { "expr": "state", "name": "isLoading" }
}
NameTypeRequiredDefaultDescription
expr"not"Yes-Expression type identifier.
operandExpressionYes-Expression to negate (should evaluate to boolean).

Example

json
{
  "kind": "if",
  "condition": {
    "expr": "not",
    "operand": { "expr": "state", "name": "isHidden" }
  },
  "then": {
    "kind": "text",
    "value": { "expr": "lit", "value": "Visible content" }
  }
}

Param Expression

Accesses action parameters (used inside action steps).

json
{ "expr": "param", "name": "value" }
{ "expr": "param", "name": "event", "path": "target.value" }
NameTypeRequiredDefaultDescription
expr"param"Yes-Expression type identifier.
namestringYes-Name of the action parameter.
pathstringNo-Dot-notation path for nested property access.

Usage in Actions

json
{
  "name": "updateInput",
  "steps": [
    {
      "do": "set",
      "target": "inputValue",
      "value": { "expr": "param", "name": "event", "path": "target.value" }
    }
  ]
}

Cond Expression

Returns different values based on a condition. Unlike the if node which controls rendering, cond evaluates to a value.

json
{
  "expr": "cond",
  "if": { "expr": "state", "name": "done" },
  "then": { "expr": "lit", "value": "Completed" },
  "else": { "expr": "lit", "value": "Pending" }
}
NameTypeRequiredDefaultDescription
expr"cond"Yes-Expression type identifier.
ifExpressionYes-Condition expression (must evaluate to boolean).
thenExpressionYes-Expression to evaluate when condition is true.
elseExpressionYes-Expression to evaluate when condition is false.

Cond vs If Node

Featurecond Expressionif Node
PurposeCompute a valueControl rendering
ReturnsA valueA view node
UsageInside text, attributes, propsView tree

Examples

json
// Conditional text label
{
  "kind": "text",
  "value": {
    "expr": "cond",
    "if": { "expr": "state", "name": "isAdmin" },
    "then": { "expr": "lit", "value": "Admin Panel" },
    "else": { "expr": "lit", "value": "User Dashboard" }
  }
}

// Conditional CSS class
{
  "kind": "element",
  "tag": "div",
  "props": {
    "class": {
      "expr": "cond",
      "if": { "expr": "state", "name": "isActive" },
      "then": { "expr": "lit", "value": "active" },
      "else": { "expr": "lit", "value": "inactive" }
    }
  }
}

// Nested cond for multiple conditions
{
  "expr": "cond",
  "if": {
    "expr": "bin",
    "op": ">",
    "left": { "expr": "state", "name": "score" },
    "right": { "expr": "lit", "value": 80 }
  },
  "then": { "expr": "lit", "value": "Excellent" },
  "else": {
    "expr": "cond",
    "if": {
      "expr": "bin",
      "op": ">",
      "left": { "expr": "state", "name": "score" },
      "right": { "expr": "lit", "value": 50 }
    },
    "then": { "expr": "lit", "value": "Good" },
    "else": { "expr": "lit", "value": "Needs Improvement" }
  }
}

Get Expression

Accesses properties from an object expression. Essential for working with object arrays in each loops.

json
{
  "expr": "get",
  "base": { "expr": "var", "name": "item" },
  "path": "title"
}
NameTypeRequiredDefaultDescription
expr"get"Yes-Expression type identifier.
baseExpressionYes-Base expression (typically a variable or state).
pathstringYes-Dot-separated path to the property.

Path Access

The path supports dot notation for nested properties:

json
// Access item.user.profile.name
{
  "expr": "get",
  "base": { "expr": "var", "name": "item" },
  "path": "user.profile.name"
}

Get vs Var with Path

Both get and var with path can access nested properties. Use get when the base is a computed expression, and var with path when accessing a simple loop variable.

json
// Using var with path (simpler for loop variables)
{ "expr": "var", "name": "user", "path": "email" }

// Using get (when base is computed or for clarity)
{
  "expr": "get",
  "base": { "expr": "var", "name": "user" },
  "path": "email"
}

Usage in Each Loop

json
{
  "kind": "each",
  "items": { "expr": "state", "name": "todos" },
  "as": "todo",
  "index": "i",
  "body": {
    "kind": "element",
    "tag": "div",
    "children": [
      {
        "kind": "text",
        "value": {
          "expr": "get",
          "base": { "expr": "var", "name": "todo" },
          "path": "title"
        }
      },
      {
        "kind": "text",
        "value": {
          "expr": "cond",
          "if": {
            "expr": "get",
            "base": { "expr": "var", "name": "todo" },
            "path": "done"
          },
          "then": { "expr": "lit", "value": " [Completed]" },
          "else": { "expr": "lit", "value": " [Pending]" }
        }
      }
    ]
  }
}

Route Expression

Accesses route parameters, query strings, or the current path in routed applications.

json
{ "expr": "route", "name": "id" }
{ "expr": "route", "name": "search", "source": "query" }
{ "expr": "route", "source": "path" }
NameTypeRequiredDefaultDescription
expr"route"Yes-Expression type identifier.
namestringNo-Name of the route parameter or query parameter.
source"param" | "query" | "path"No"param"Source of the route value.

Source Types

SourceDescriptionExample URLExpression
paramDynamic path segment/posts/123{ "expr": "route", "name": "id" }
queryURL query parameter/search?q=test{ "expr": "route", "name": "q", "source": "query" }
pathFull current path/docs/intro{ "expr": "route", "source": "path" }

Example

json
{
  "route": {
    "path": "/blog/[slug]"
  },
  "view": {
    "kind": "element",
    "tag": "h1",
    "children": [{
      "kind": "text",
      "value": { "expr": "route", "name": "slug" }
    }]
  }
}

Index Expression

Dynamically accesses array elements or object properties using a computed key.

json
{
  "expr": "index",
  "base": { "expr": "state", "name": "items" },
  "key": { "expr": "state", "name": "selectedIndex" }
}
NameTypeRequiredDefaultDescription
expr"index"Yes-Expression type identifier.
baseExpressionYes-Base expression (array or object).
keyExpressionYes-Key expression (number for arrays, string for objects).

Array Access

json
{
  "expr": "index",
  "base": { "expr": "state", "name": "users" },
  "key": { "expr": "lit", "value": 0 }
}

Object Access with Dynamic Key

json
{
  "expr": "index",
  "base": { "expr": "import", "name": "translations" },
  "key": { "expr": "state", "name": "currentLanguage" }
}

Import Expression

Accesses data from imported JSON files defined in the imports property.

json
{ "expr": "import", "name": "config" }
{ "expr": "import", "name": "config", "path": "siteName" }
NameTypeRequiredDefaultDescription
expr"import"Yes-Expression type identifier.
namestringYes-Name of the import (key in the imports object).
pathstringNo-Dot-notation path for nested property access.

Example

json
{
  "imports": {
    "config": "../data/config.json",
    "nav": "../data/navigation.json"
  },
  "view": {
    "kind": "element",
    "tag": "header",
    "children": [{
      "kind": "text",
      "value": { "expr": "import", "name": "config", "path": "siteName" }
    }]
  }
}

Cookie Expression

Reads a value from cookies. Primarily used in state initial for SSR/SSG-safe persistence (e.g., theme preference).

json
{ "expr": "cookie", "key": "theme", "default": "dark" }
NameTypeRequiredDefaultDescription
expr"cookie"Yes-Expression type identifier.
keystringYes-Cookie name to read.
defaultstringYes-Fallback value when cookie is not set.

Usage in State Initial

Cookie expressions are designed for state initialization, enabling SSR/SSG-safe persistence:

json
{
  "state": {
    "theme": {
      "type": "string",
      "initial": { "expr": "cookie", "key": "theme", "default": "dark" }
    }
  }
}

How It Works

EnvironmentBehavior
SSR/SSGReads cookie from HTTP request headers
ClientReads cookie from document.cookie
No cookieReturns the default value

Data Expression

Accesses data from build-time data sources (glob, file, or API). Used primarily with @constela/start for SSG.

json
{ "expr": "data", "name": "post" }
{ "expr": "data", "name": "post", "path": "frontmatter.title" }
NameTypeRequiredDefaultDescription
expr"data"Yes-Expression type identifier.
namestringYes-Name of the data source (key in the data object).
pathstringNo-Dot-notation path for nested property access.

Example with MDX Data Source

json
{
  "data": {
    "docs": {
      "type": "glob",
      "pattern": "content/docs/*.mdx",
      "transform": "mdx"
    }
  },
  "view": {
    "kind": "element",
    "tag": "article",
    "children": [
      {
        "kind": "element",
        "tag": "h1",
        "children": [{
          "kind": "text",
          "value": { "expr": "data", "name": "docs", "path": "frontmatter.title" }
        }]
      },
      {
        "kind": "markdown",
        "content": { "expr": "data", "name": "docs", "path": "content" }
      }
    ]
  }
}

Ref Expression

References a DOM element by its ref attribute. Used for JavaScript interop.

json
{ "expr": "ref", "name": "editorContainer" }
NameTypeRequiredDefaultDescription
expr"ref"Yes-Expression type identifier.
namestringYes-Name of the ref (matches the ref attribute on an element).

Example

json
{
  "view": {
    "kind": "element",
    "tag": "div",
    "props": {
      "ref": { "expr": "lit", "value": "editorContainer" }
    }
  },
  "lifecycle": {
    "onMount": "initEditor"
  },
  "actions": [{
    "name": "initEditor",
    "steps": [{
      "do": "call",
      "target": { "expr": "var", "name": "monaco", "path": "editor.create" },
      "args": [
        { "expr": "ref", "name": "editorContainer" },
        { "expr": "lit", "value": { "language": "json" } }
      ]
    }]
  }]
}

Style Expression

Applies style presets with variants, similar to CVA (Class Variance Authority) or Tailwind Variants.

json
{
  "expr": "style",
  "name": "button",
  "variants": {
    "variant": { "expr": "lit", "value": "primary" },
    "size": { "expr": "lit", "value": "lg" }
  }
}
NameTypeRequiredDefaultDescription
expr"style"Yes-Expression type identifier.
namestringYes-Name of the style preset defined in the styles object.
variantsRecord<string, Expression>No-Variant selections to apply. Values can be literal or dynamic expressions.

Example

json
{
  "styles": {
    "button": {
      "base": "px-4 py-2 rounded font-medium",
      "variants": {
        "variant": {
          "primary": "bg-blue-500 text-white",
          "secondary": "bg-gray-200 text-gray-800"
        },
        "size": {
          "sm": "text-sm",
          "md": "text-base",
          "lg": "text-lg"
        }
      },
      "defaultVariants": {
        "variant": "primary",
        "size": "md"
      }
    }
  },
  "view": {
    "kind": "element",
    "tag": "button",
    "props": {
      "className": {
        "expr": "style",
        "name": "button",
        "variants": {
          "variant": { "expr": "lit", "value": "primary" }
        }
      }
    },
    "children": [{ "kind": "text", "value": { "expr": "lit", "value": "Click me" } }]
  }
}

Dynamic Variants

Combine with state for dynamic styling:

json
{
  "state": {
    "isActive": { "type": "boolean", "initial": false }
  },
  "view": {
    "props": {
      "className": {
        "expr": "style",
        "name": "button",
        "variants": {
          "variant": {
            "expr": "cond",
            "if": { "expr": "state", "name": "isActive" },
            "then": { "expr": "lit", "value": "primary" },
            "else": { "expr": "lit", "value": "secondary" }
          }
        }
      }
    }
  }
}

Concat Expression

Concatenates multiple expressions into a single string. Each expression is evaluated and converted to a string, then joined together.

json
{
  "expr": "concat",
  "items": [
    { "expr": "lit", "value": "Hello, " },
    { "expr": "var", "name": "user", "path": "name" },
    { "expr": "lit", "value": "!" }
  ]
}
NameTypeRequiredDefaultDescription
expr"concat"Yes-Expression type identifier.
itemsExpression[]Yes-Array of expressions to concatenate. Each is evaluated and converted to string.

Dynamic Class Names

A common use case is building dynamic CSS class names:

json
{
  "kind": "element",
  "tag": "div",
  "props": {
    "class": {
      "expr": "concat",
      "items": [
        { "expr": "lit", "value": "avatar rounded-full " },
        { "expr": "var", "name": "user", "path": "avatarSize" },
        { "expr": "lit", "value": " " },
        { "expr": "var", "name": "user", "path": "avatarColor" }
      ]
    }
  }
}

Combining with Conditionals

json
{
  "expr": "concat",
  "items": [
    { "expr": "lit", "value": "btn " },
    {
      "expr": "cond",
      "if": { "expr": "state", "name": "isActive" },
      "then": { "expr": "lit", "value": "btn-active" },
      "else": { "expr": "lit", "value": "btn-inactive" }
    }
  ]
}

Validity Expression

Accesses HTML5 Constraint Validation API for form elements. Returns validation state from the browser's built-in validation.

json
{ "expr": "validity", "ref": "emailInput", "property": "valid" }
{ "expr": "validity", "ref": "emailInput", "property": "message" }
NameTypeRequiredDefaultDescription
expr"validity"Yes-Expression type identifier.
refstringYes-Name of the ref on the form element to check validity for.
propertystringNo"valid"Validity property to access. Defaults to 'valid'.

Validity Properties

PropertyTypeDescription
validbooleantrue if all constraints pass
valueMissingbooleantrue if required field is empty
typeMismatchbooleantrue if value doesn't match type (email, url, etc.)
patternMismatchbooleantrue if value doesn't match pattern attribute
tooLongbooleantrue if value exceeds maxLength
tooShortbooleantrue if value is under minLength
rangeUnderflowbooleantrue if number is below min
rangeOverflowbooleantrue if number exceeds max
stepMismatchbooleantrue if value doesn't match step
customErrorbooleantrue if custom validity was set
messagestringBrowser's localized validation message

Example: Email Validation

json
{
  "state": {},
  "actions": [],
  "view": {
    "kind": "element",
    "tag": "div",
    "children": [
      {
        "kind": "element",
        "tag": "input",
        "ref": "emailInput",
        "props": {
          "type": { "expr": "lit", "value": "email" },
          "required": { "expr": "lit", "value": true },
          "placeholder": { "expr": "lit", "value": "Enter your email" }
        }
      },
      {
        "kind": "if",
        "condition": {
          "expr": "not",
          "operand": { "expr": "validity", "ref": "emailInput", "property": "valid" }
        },
        "then": {
          "kind": "element",
          "tag": "span",
          "props": { "className": { "expr": "lit", "value": "text-red-500 text-sm" } },
          "children": [{
            "kind": "text",
            "value": { "expr": "validity", "ref": "emailInput", "property": "message" }
          }]
        }
      }
    ]
  }
}

Example: Password Strength

json
{
  "kind": "element",
  "tag": "input",
  "ref": "passwordInput",
  "props": {
    "type": { "expr": "lit", "value": "password" },
    "minLength": { "expr": "lit", "value": 8 },
    "pattern": { "expr": "lit", "value": ".*[A-Z].*" }
  }
},
{
  "kind": "if",
  "condition": { "expr": "validity", "ref": "passwordInput", "property": "tooShort" },
  "then": {
    "kind": "text",
    "value": { "expr": "lit", "value": "Password must be at least 8 characters" }
  }
},
{
  "kind": "if",
  "condition": { "expr": "validity", "ref": "passwordInput", "property": "patternMismatch" },
  "then": {
    "kind": "text",
    "value": { "expr": "lit", "value": "Password must contain an uppercase letter" }
  }
}

Call Expression

Calls a method on arrays, strings, Math, or Date objects.

Syntax

json
{
  "expr": "call",
  "target": <Expression>,
  "method": "methodName",
  "args": [<Expression>, ...]
}
NameTypeRequiredDefaultDescription
expr"call"Yes-Expression type identifier.
targetExpressionYes-The target object (array, string, or Math/Date).
methodstringYes-Method name to call.
argsExpression[]No-Arguments to pass to the method.

Array Methods

MethodDescription
lengthArray length
atElement at index (supports negative)
includesCheck if contains value
sliceExtract portion
indexOfFind index of value
joinJoin elements to string
filterFilter with lambda
mapTransform with lambda
findFind first matching
findIndexFind index of first matching
someCheck if any match
everyCheck if all match

String Methods

MethodDescription
lengthString length
charAtCharacter at index
substringExtract substring
sliceExtract portion
splitSplit to array
trimRemove whitespace
toUpperCaseConvert to uppercase
toLowerCaseConvert to lowercase
replaceReplace first match
includesCheck if contains
startsWithCheck prefix
endsWithCheck suffix
indexOfFind index

Math Methods

MethodDescription
minMinimum of values
maxMaximum of values
roundRound to nearest
floorRound down
ceilRound up
absAbsolute value
sqrtSquare root
powPower
randomRandom 0-1

Date Methods

Static: now, parse

Instance: toISOString, getTime, getFullYear, getMonth, getDate, getHours, getMinutes, getSeconds, getMilliseconds

Examples

json
// Get array length
{ "expr": "call", "target": { "expr": "state", "name": "items" }, "method": "length" }

// Filter completed todos
{
  "expr": "call",
  "target": { "expr": "state", "name": "todos" },
  "method": "filter",
  "args": [{
    "expr": "lambda",
    "param": "todo",
    "body": { "expr": "get", "base": { "expr": "var", "name": "todo" }, "path": "completed" }
  }]
}

// Math.max
{
  "expr": "call",
  "target": { "expr": "var", "name": "Math" },
  "method": "max",
  "args": [{ "expr": "lit", "value": 10 }, { "expr": "state", "name": "count" }]
}

Lambda Expression

Anonymous function for array methods like filter, map, find.

Syntax

json
{
  "expr": "lambda",
  "param": "item",
  "index": "i",
  "body": <Expression>
}
NameTypeRequiredDefaultDescription
expr"lambda"Yes-Expression type identifier.
paramstringYes-Parameter name for the current item.
indexstringNo-Optional parameter name for the current index.
bodyExpressionYes-Expression to evaluate for each item.

Example

json
{
  "expr": "call",
  "target": { "expr": "state", "name": "users" },
  "method": "map",
  "args": [{
    "expr": "lambda",
    "param": "user",
    "index": "i",
    "body": { "expr": "get", "base": { "expr": "var", "name": "user" }, "path": "name" }
  }]
}

Array Expression

Constructs an array dynamically from expressions. Useful for building arrays where elements can be variables, function call results, or any other expression types.

Syntax

json
{
  "expr": "array",
  "elements": [<Expression>, ...]
}
NameTypeRequiredDefaultDescription
expr"array"Yes-Expression type identifier.
elementsExpression[]Yes-Array of expressions to evaluate and include in the result array.

Basic Examples

json
// Empty array
{ "expr": "array", "elements": [] }

// Array of literals
{
  "expr": "array",
  "elements": [
    { "expr": "lit", "value": 1 },
    { "expr": "lit", "value": 2 },
    { "expr": "lit", "value": 3 }
  ]
}

// Array with state values
{
  "expr": "array",
  "elements": [
    { "expr": "state", "name": "config" },
    { "expr": "state", "name": "theme" },
    { "expr": "lit", "value": "default" }
  ]
}

CodeMirror Extensions Pattern

A common use case is building extension arrays for libraries like CodeMirror:

json
// Equivalent to: [basicSetup, json()]
{
  "expr": "array",
  "elements": [
    { "expr": "var", "name": "basicSetup" },
    {
      "expr": "call",
      "target": { "expr": "var", "name": "json" },
      "method": "apply",
      "args": []
    }
  ]
}

Nested Arrays

json
// [[1, 2], [3, 4]]
{
  "expr": "array",
  "elements": [
    {
      "expr": "array",
      "elements": [
        { "expr": "lit", "value": 1 },
        { "expr": "lit", "value": 2 }
      ]
    },
    {
      "expr": "array",
      "elements": [
        { "expr": "lit", "value": 3 },
        { "expr": "lit", "value": 4 }
      ]
    }
  ]
}

Combining with Conditionals

json
{
  "expr": "array",
  "elements": [
    { "expr": "var", "name": "baseConfig" },
    {
      "expr": "cond",
      "if": { "expr": "state", "name": "isDebug" },
      "then": { "expr": "var", "name": "debugPlugin" },
      "else": { "expr": "lit", "value": null }
    }
  ]
}