The frontend template engine supports one-way and two-way bindings and event handlers. All expressions are evaluated in the current scope (global + loop/block context).Documentation Index
Fetch the complete documentation index at: https://docs.elasticfunnels.io/llms.txt
Use this file to discover all available pages before exploring further.
Text and HTML bindings
ef-text="expression" (or data-ef-text)
Sets the element’s textContent from the expression (HTML is escaped). Updates automatically when scope changes.
ef-html="expression" (or data-ef-html)
Sets the element’s innerHTML from the expression. Use only with trusted content — no automatic escaping. Risk of XSS if the value comes from user input.
data-ef-text or [[ ... ]] when the value is not fully trusted.
One-way attribute bindings: ef-href, ef-title, ef-alt, ef-placeholder
Use these when you want scope-driven attributes without writing full [[ ... ]] strings in markup.
ef-href/data-ef-hrefef-title/data-ef-titleef-alt/data-ef-altef-placeholder/data-ef-placeholder
Two-way form binding: ef-value / data-ef-value / data-template-value
ef-value="path" (or data-ef-value / data-template-value) on input, select, or textarea binds the control to a dot path in scope (e.g. checkout.customer.email, billing.name).
- Scope → element: Engine sets value/checked from scope automatically on updates.
- Element → scope: On
inputorchange, the engine writes the control’s value back to the path (creating nested objects as needed), then updates dependent UI.
Supported controls
| Control | Path type | Behavior |
|---|---|---|
input text, email, tel, etc. | String | value ↔ scope path |
input type="checkbox" | Boolean | checked ↔ scope path |
input type="radio" | Selected value (string) | One ef-value/data-ef-value/data-template-value on a radio (or each); path holds selected value; same name = one group. |
textarea | String | value ↔ scope path |
select | String (single) or array (multiple) | Single: path is string; multiple: path is array of selected option values |
Example: checkout fields
checkout.shipping_same_as_billing updates and dependent blocks (like <template-if data-condition="!checkout.shipping_same_as_billing">) react automatically.
data-set-onload
When present, if the scope path is undefined on the first run, the element’s current value/checked is written to scope. Useful so HTML defaults (e.g. checked on a checkbox) drive template logic on load.
One-way bindings: :checked, :disabled, :value
Vue-style one-way bindings: the expression is evaluated and the DOM property is set on each update. The attribute is removed after first apply and the expression is stored in memory so the DOM stays clean.
:checked="expression"— Setselement.checked(e.g.:checked="bumpSelected").:disabled="expression"— Setselement.disabled.:value="expression"— Setselement.value.
ef-value (or aliases) for two-way binding.
Event handlers: @click and others
@click="expression" runs the expression when the element (or a child) is clicked. The expression is evaluated in a context that includes $event / event (the DOM event) and $el / $target (element). Assignments in the expression (e.g. items = [], item.open = !item.open) mutate scope and the UI re-renders automatically.
Aliases
@click— Short form.data-ef-on:click,data-ef-on-click,data-ef-click— Attribute forms.
@submit, @change, @input, @blur, @focus, etc. The engine discovers used event names from the DOM and binds them once.
Examples
false from the expression calls preventDefault() on the event.
Cart and bumps
For cart quantity and remove, prefer the cart plugin’s data attributes so behavior is consistent without custom script:- Decrease qty:
data-cart-qty-minusanddata-code="[[ item.code ]]"(so the plugin gets the actual code); optionaldata-disable-when-oneto disable whenitem.quantity <= 1. - Increase qty:
data-cart-qty-plusanddata-code="[[ item.code ]]". - Remove:
data-cart-qty-removeanddata-code="[[ item.code ]]".
window.ef.addToCart(code, options?, quantity?), ef.setCartQuantity(code, quantity), ef.removeFromCart(code, allowClear?) if the app exposes window.ef.
Lifecycle & visibility directives
Element-level handlers that run when an element enters the DOM, leaves the DOM, or scrolls into the viewport. They share the same expression model and alias families as@click — the expression runs in the current scope and can read $el (the element itself).
@mounted="expression"
Runs once after the element is inserted into the live DOM. Useful for initializing third-party widgets, setting focus, or kicking off animations on elements rendered by template-if or template-foreach.
- Fires once per element instance. Re-renders of the same element do not re-fire it.
- Hiding a
template-ifbranch and showing it again creates a new element instance, so@mountedruns again. - Deferred to the next animation frame so layout has settled before the handler runs.
@unmounted="expression"
Runs just before the element is removed from the DOM (e.g. when a template-if condition flips false or a template-foreach item drops out).
@mounted.
@visible="expression"
Runs when the element scrolls into the viewport, backed by an IntersectionObserver under the hood.
@visible.once(default) — Fires only the first time the element enters the viewport, then disconnects.@visible.every— Fires every time the element re-enters the viewport.
data-ef-visible-threshold="0..1"— Fraction of the element that must be visible to fire (default0: any pixel).data-ef-visible-margin="100px 0px"—rootMarginpassed to the observer; positive values fire earlier (before the element actually scrolls into view).
$event as the IntersectionObserverEntry when fired.
Aliases
All three directives accept the same alias families as@click:
| Short | data-ef-on: | data-ef-on- | data-ef- |
|---|---|---|---|
@mounted | data-ef-on:mounted | data-ef-on-mounted | data-ef-mounted |
@unmounted | data-ef-on:unmounted | data-ef-on-unmounted | data-ef-unmounted |
@visible | data-ef-on:visible | data-ef-on-visible | data-ef-visible |
data-ef-on:visible.once, data-ef-on-visible-once, data-ef-visible-every.
When to prefer the JS API
For watchers tied to scope paths rather than DOM elements, usewindow.ef.template.watch(path, fn, { immediate, deep }) — see Scope & Data. Use the markup directives when the trigger is DOM lifecycle or viewport visibility of a specific element.
Reactivity summary
[[ expression ]]— Re-evaluated automatically after relevant scope changes.- Mounted
template-ifandtemplate-foreach— Re-render automatically when dependencies change. ef-value/ aliases — Scope → element on updates; element → scope on input / change.ef-text/ef-html/ef-src/ef-href/ef-title/ef-alt/ef-placeholder/:checked/:disabled/:value— Applied on reactive updates.@mounted/@unmounted/@visible— Run when the element is inserted into / removed from the DOM, or first scrolls into the viewport.