Expressions
WildflowerJS binding attributes accept both simple property names and inline JavaScript expressions, enabling dynamic values without computed properties.
Overview
Most binding attributes accept either a simple property name or a JavaScript expression. Simple property names resolve directly from component state or computed properties. Expressions are evaluated at render time and re-evaluated whenever their dependencies change.
<!-- Simple property reference -->
<span data-bind="username"></span>
<!-- Expression with arithmetic -->
<span data-bind="price * quantity"></span>
<!-- Expression with ternary -->
<span data-bind="isActive ? 'Active' : 'Inactive'"></span>
The framework automatically detects whether a binding value is a simple property name or an expression by looking for operators, parentheses, or ternary syntax.
Where Expressions Work
Expressions are supported in these binding attributes:
| Attribute | Example | Purpose |
|---|---|---|
data-bind |
data-bind="price * qty" |
Text content |
data-bind-html |
data-bind-html="htmlContent" |
HTML content |
data-bind-class |
data-bind-class="isActive ? 'on' : 'off'" |
CSS classes |
data-bind-style |
data-bind-style="{ color: isError ? 'red' : 'black' }" |
Inline styles |
data-bind-attr |
data-bind-attr="{ disabled: !isValid }" |
HTML attributes |
data-show |
data-show="items.length > 0" |
Visibility toggle |
data-render |
data-render="isLoggedIn && hasPermission" |
Conditional rendering |
Syntax Reference
Property References
Reference state properties and computed properties by name. Nested properties use dot notation:
<span data-bind="count"></span>
<span data-bind="user.name"></span>
<span data-bind="address.city"></span>
Arithmetic
<span data-bind="price * quantity"></span>
<span data-bind="subtotal + tax"></span>
<span data-bind="total / count"></span>
<span data-bind="index % 2"></span>
<span data-bind="(price * quantity) + shipping"></span>
Comparisons
<div data-show="count > 0">Has items</div>
<div data-show="status === 'active'">Active</div>
<div data-show="score >= 90">High score</div>
<div data-show="type !== 'hidden'">Visible</div>
Logical Operators
<div data-show="isLoggedIn && isAdmin">Admin Panel</div>
<div data-show="hasError || isLoading">Status</div>
<span data-bind="nickname || username"></span>
Ternary Operator
<span data-bind="isOnline ? 'Online' : 'Offline'"></span>
<span data-bind-class="isActive ? 'btn-primary' : 'btn-secondary'"></span>
<span data-bind="count === 1 ? 'item' : 'items'"></span>
Negation
<!-- Simple negation (not treated as an expression) -->
<div data-show="!isHidden">Visible</div>
<!-- Negation in expressions -->
<div data-show="!isLoading && items.length > 0">Ready</div>
<div data-bind-attr="{ disabled: !isValid }"></div>
String and Number Literals
<span data-bind="count + ' items'"></span>
<span data-bind="score > 100 ? 'High' : 'Low'"></span>
Store Access
Access store values in expressions using the $storeName.property shorthand:
<span data-bind="$user.name"></span>
<div data-show="$cart.itemCount > 0">Items in cart</div>
<span data-bind="$settings.theme === 'dark' ? 'Dark Mode' : 'Light Mode'"></span>
The $store.path syntax is converted to external('store', 'path') internally. See Basic Stores for more on store subscriptions.
Expressions vs Computed Properties
Both inline expressions and computed properties can derive values from state. Choose based on complexity:
| Use | When |
|---|---|
| Inline expression | Simple, one-off calculations: a comparison, a ternary, basic arithmetic |
| Computed property | Complex logic, reused across multiple bindings, or multi-step calculations |
<!-- Inline: fine for simple cases -->
<span data-bind-class="isActive ? 'active' : ''"></span>
<span data-bind="price * quantity"></span>
<!-- Computed: better for complex logic -->
<span data-bind="formattedTotal"></span>
<span data-bind-class="statusClass"></span>
wildflower.component('invoice', {
state: {
price: 29.99,
quantity: 3,
taxRate: 0.08
},
computed: {
formattedTotal() {
var total = this.price * this.quantity
var tax = total * this.taxRate
return '$' + (total + tax).toFixed(2)
},
statusClass() {
if (this.quantity === 0) return 'text-muted'
if (this.quantity > 10) return 'text-success fw-bold'
return 'text-primary'
}
}
})
As a rule of thumb: if the expression needs more than one operator or is used in multiple places, extract it into a computed property.
Content Security Policy (CSP)
By default, WildflowerJS compiles expressions using new Function() for best performance. In environments with strict Content Security Policy headers that block unsafe-eval, the framework automatically detects this and switches to a built-in AST-based expression parser. Auto-detection works by attempting one new Function() call at startup; under a strict policy that attempt is blocked and reported as a single benign securitypolicyviolation before the framework falls back.
Recommended: the data-csp-safe attribute
On pages served with a strict CSP, add data-csp-safe to the framework script tag. The framework then starts directly in CSP-safe mode and never attempts dynamic code execution at all, so the page generates zero CSP violations and zero violation reports:
<script src="wildflower.min.js" data-csp-safe defer></script>
This matters on sites that use report-uri or report-to: without the attribute, the startup capability probe files one violation report per page load with your security tooling.
See it live: an interactive list running under default-src 'none' with a violation counter reading zero.
Runtime switch: wildflower.config()
When the script tag isn't under your control, switch at runtime instead:
wildflower.config({ forceCSPMode: true });
Expressions compiled after the call use the CSP-safe parser. This runs after the framework has already loaded, so it cannot suppress the startup probe; prefer the attribute when you control the script tag.
What CSP Mode Supports
The AST-based parser supports the same expression syntax used in bindings:
- Arithmetic:
+,-,*,/,% - Comparison:
==,!=,===,!==,<,>,<=,>= - Logical:
&&,||,! - Bitwise:
&,|,^,~,<<,>>,>>> - Ternary:
condition ? a : b - Unary:
-x,+x,!x,~x - Property access: dot notation (
user.name) and bracket notation (items[0]) - Function calls:
external()for store access - Literals: strings, numbers,
true,false,null,undefined, arrays - Grouping: parentheses
(a + b) * c
CSP Mode Limitations
The AST parser does not support:
- Method calls (e.g.,
str.toUpperCase()); use a computed property instead - Arrow functions
- Template literals (
`hello ${name}`) - Destructuring or spread operators
- Global objects (
Math,Date, etc.); use computed properties for these
new Function() and can access JavaScript globals like Math.round() or Date.now(). These do not work in CSP mode. If you need CSP compliance, use computed properties for any logic that requires global objects or method calls.
Security
The CSP expression evaluator includes built-in security protections:
- No global access:
window,document,fetch,eval, and other browser globals are blocked - No prototype pollution: Access to
__proto__,constructor, andprototypeis blocked - Scope-limited: Expressions can only reference component state, computed properties, and store data via
external()