Expressions
Expressions render dynamic values inside HTML templates using curly braces. They can be used in text and attribute values, in both pages and components.
This is the main way to bind data into markup without leaving the normal Lediv workflow.
Expressions run in a secure subset of JavaScript. Not every JavaScript feature is available by design.
How scope works
Every expression is evaluated against the current scope. Scope is the set of values available at that point in the template.
At page level, scope starts with variables declared in regular
<script> blocks and $context. In components, scope includes
$context and also $props. Inside loops, each iteration adds its own
local variables (for example item and index).
<script>
const plans = [{ name: 'Starter' }, { name: 'Pro' }];
const currency = 'EUR';
</script>
<li le-each="{plans as plan, i}">{i + 1}. {plan.name} ({currency})</li>
In this example, currency comes from page/component scope, while
plan and i come from the loop scope.
For loop syntax and rendering patterns, see Conditionals and Loops.
What $context and $props mean
$context contains data related to the current page. It is available in the page and
in all component instances rendered inside that page. A common example is
$context.page.
$props are the input values passed to one component instance. They are available
only inside components, and allow the same component to render different content in each usage.
| Object | Available in | Typical use |
|---|---|---|
$context | Pages and components | Read app-level context values, like current page path. |
$props | Components only | Receive values from component usage attributes. |
$editor | Pages and components, editor only |
Editor-only namespace with isActive, variant, and
variants properties. See
Editable Components.
|
$context example (page data)
<!-- Page file -->
<script>
const currentPath = $context.page;
</script>
<small>{currentPath}</small> $props example (component attributes)
<!-- Page usage -->
<Hero title="Build faster" ctaLabel="{primaryCta}" />
<!-- Hero.html -->
<script>
const { title, ctaLabel } = $props;
</script> Use expressions in text and attributes
Wrap any expression with {...}. The same syntax works for text content and
for attribute values.
<script>
const product = 'Starter';
const price = 19;
const slug = 'starter';
</script>
<h2>{product} plan</h2>
<p>From {price} €/month</p>
<a href="/pricing/{slug}">View details</a>
Always wrap HTML attribute values in double quotes, including expressions:
href="{url}" and not href={url}.
Supported data types
Expressions can read and produce these value types:
| Type | Examples |
|---|---|
| String | "hello", 'world' |
| Number | 42, 3.14 |
| Boolean | true, false |
| Null values | null, undefined |
| Array | [1, 2, 3] (usually consumed with loops or indexing) |
| Object | {label: "Pro", price: 19} (usually consumed via property access)
|
Scope values should be plain data (primitives, plain objects, and plain arrays). Functions, getters/setters, and symbol keys are blocked.
When the final value is null or undefined, rendered output is an empty
string.
Objects are intended for access patterns like plan.name, not direct text rendering
of the full object.
Supported operators and syntax
Common expression syntax supported in templates.
- Arithmetic:
+,-,*,/,% - Comparison:
==,!=,===,!==,>,>=,<,<= - Logic:
&&,||,!,?? - Ternary:
condition ? valueA : valueB - Template literals:
`Hello ${name}` - Property/index access:
user.name,items[0] - Method calls (restricted):
items.find((item) => ...),name.trim()
Calls are intentionally limited for safety. Top-level function calls like
format(price) are not supported.
Allowed methods:
- Array:
find,some,map,filter,every,includes,reduce - String:
includes,startsWith,endsWith,toLowerCase,toUpperCase,trim,slice
Unsupported syntax
Some JavaScript syntax is intentionally unsupported in templates, including optional chaining,
this, new, await, import(), tagged
templates, update operators like count++, and sequence expressions.
Where expression values come from
Expressions are evaluated against the current scope. That scope includes variables declared in
regular <script> blocks and loop variables, plus $context and (in
components) $props.
<script>
const { title } = $props;
const pagePath = $context.page;
const label = title || 'Untitled';
</script>
<h1>{label}</h1>
<p>Current path: {pagePath}</p> Keep script declarations simple. One variable declaration per statement is the safest pattern for predictable expression scope.
Output behavior
If an expression returns null, undefined, or fails to evaluate, the
rendered output is an empty string.
Text expression output is escaped before rendering, so it is treated as text, not as raw HTML.
Show braces literally
When braces should be displayed as plain text (for example in docs snippets), use
le-raw on the container element.
<pre le-raw><code>
<p>{title}</p>
</code></pre>