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.
Forcing CSP-Safe Mode
If auto-detection doesn't work in your environment, force CSP-safe mode explicitly:
wildflower.config({ forceCSPMode: true });
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()