Use
[[ ]] for frontend expressions. {{ }} is reserved for the backend Template Engine. Both can appear on the same page.Conditionals: template-if, template-else-if, template-else
Show one block among several based on a JavaScript expression evaluated in the current scope.
template-if
- Attribute:
data-condition="expression" - Behavior: When the expression is truthy, the element’s inner HTML is rendered; otherwise it is not. The
<template-if>element itself is replaced by that content.
Sibling template-else
A <template-else> immediately after a <template-if> (or after a chain of template-else-if) is the fallback when no condition matches. It has no data-condition.
template-else-if
Chain multiple conditions. The first matching branch is shown; if none match, the optional template-else is shown.
What you can use in data-condition
- Dot paths:
checkout.coupon.applied,query.coupon,items.length - Comparisons:
cartItems.length > 0,item.quantity === 1 - Functions:
cartCount(cartItems) > 0,checkout.selectedBumpLines && checkout.selectedBumpLines.length > 0 - Literals:
data-condition="true"ordata-condition="false"are supported
> for >, & for &, < for < (e.g. data-condition="cartItems.length > 1").
Expressions run in a context that includes window.efScope and any loop variable (e.g. item inside a template-foreach).
Loops: template-foreach
Repeat a block once per element in an array (or iterable). The element is replaced by the repeated content.
Preferred form: data-each
item— Variable name for the current element (you can choose any name).cartItems— Expression that must evaluate to an array (or iterable) in scope.
Optional index
Use(item, i) in array or item, i in array to get a zero-based index:
Aliases and fallbacks
data-for— Alias fordata-each(same meaning).- Legacy: You can use
data-item,data-index, anddata-arrayinstead ofdata-eachif needed.data-itemanddata-arraycan also be used together withdata-eachwhen the engine expects them (e.g. for internal loop variable names), as in some production checkout templates.
Empty arrays
When the array is empty, the loop renders nothing. Some integrations support an optional empty content (e.g. “Your cart is empty”) via configuration; the default behavior is to output no nodes.Scope inside the loop
Inside the block,item (and i if you declared it) are in scope. You can also access parent scope (e.g. checkout.currency, cartItems). Nested <template-if> and <template-foreach> are supported.
Variables: template-set and template-vars
template-set
Define a local variable for the template. The element is removed after processing; only the variable is set in the current context.
data-variable="name"— Variable name (single segment, e.g.totalorlabel).data-value="expression"— Expression to evaluate; result is stored inname.
template-vars / <template data-ef-vars>
Enables [[ var.name ]] and other expressions in the content of the element without requiring a wrapping template-if or template-foreach. The element is replaced by its inner content; that content is then processed (conditions, loops, and variable replacement run on it).
Use <template-vars> or <template data-ef-vars> when you have a block where the only dynamic part is [[ ... ]] and you want to avoid an extra conditional.
Expressions: [[ ... ]]
[[ expression ]] is replaced by the result of the expression, evaluated in the current scope (global scope + loop/block context).
Where it works
- Text nodes:
Price: [[ item.price ]] - Attribute values:
src="[[ item.image ]]",data-code="[[ item.code ]]",required="[[ f.required ? 'required' : '' ]]" - Anywhere inside processed template content (e.g. inside
template-ifortemplate-foreach)
data-code="[[ item.code ]]" so the plugin receives the actual product code string. Unquoted data-code="item.code" may still be supported by the engine in some contexts.
What you can write inside [[ ]]
- Dot paths:
item.name,checkout.total,checkout.customer.email - Expressions:
item.price * item.quantity,item.open ? 'Hide' : 'Show' - Function calls:
formatPrice(item.price, currency),upper(item.name),cartCount(cartItems)
registerTemplateFunction.
Examples
| You write | Meaning | Example result |
|---|---|---|
[[ item.name ]] | Current item’s name | ”1 Bottle” |
[[ item.price ]] | Unit price (often pre-formatted) | “$69.00” |
[[ item.total ]] | Line total (price × qty) | “$552.00” |
[[ checkout.total ]] | Checkout total (formatted) | “$99.00” |
[[ formatPrice(amount, currency) ]] | Format a number as currency | ”$49.99” |
[[ item.open ? 'Hide details' : 'Show details' ]] | Ternary | ”Show details” |
Attribute binding shortcuts (ef-*)
For many UI components, attribute bindings are easier to maintain than inline token strings:
ef-text, ef-html, ef-src, ef-href, ef-title, ef-alt, ef-placeholder, and ef-value (plus data- forms).
These can be added from the page builder Data Attributes panel (right sidebar) when an element is selected.
Cloaking
To avoid a flash of raw[[ ... ]] or the wrong branch before the template engine runs:
[data-ef-cloak]— Add this attribute to elements that should be hidden until processed. The engine may remove it after processing. Include CSS:[data-ef-cloak] { display: none !important; }.- Template tags — Include CSS that hides the custom elements until processed:
template-foreach,template-if,template-else,template-setwithdisplay: none !important. - In some deployments,
data-frontend-template="true"is used ontemplate-if,template-else, andtemplate-foreachto mark frontend-processed blocks.
Processing order
The engine runs directives in a fixed order:- templateVars — Unwrap
<template-vars>/<template data-ef-vars>so inner[[ ]]can be processed. - set — Process
<template-set>(set variables, remove elements). - foreach — Expand
<template-foreach>(in a one-shot process path) or re-render mounted foreach on update. - if — Expand
<template-if>(and sibling else-if/else) or re-render mounted if on update. - vars — Replace remaining
[[ ... ]]in text and attributes.
template-if and template-foreach are mounted: the original tags are replaced by comment anchors and an update function is registered. When reactive scope changes happen, those functions re-evaluate and only affected parts of the DOM update.
Next: Scope & Data.