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" }
    }]
  }
}

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" }
    }
  ]
}