HTML Attributes Reference
Every data attribute WildflowerJS reads, with its syntax, an example and the builds that include it.
wf- prefix: data-wf-bind, data-wf-event-key-enter, data-wf-model-number and so on. When an element carries both forms, the data-wf-* one wins. To stop WildflowerJS reading the plain data-* forms at all, for example beside another library that uses data-action, turn on exclusive mode with data-wf-prefix="true" on the script tag or wildflower.setWfPrefixMode(true). Markers the framework writes for itself, such as data-component-id, keep their plain names in both modes.
At a glance
Builds: all means every build, nano included. Lists ship in mini, lite and above; pools in mini-pool, lite and above; portals, transitions and plugins in standard, spa and full; the router in spa and full; queries and SSR in full.
| Attribute | Purpose | Builds |
|---|---|---|
| Components and binding | ||
| data-component | Marks a component root | all |
| data-bind | Text content from state | all |
| data-bind-html | innerHTML from state | all |
| data-bind-class | Classes from an expression | all |
| data-bind-style | Inline styles from an expression | all |
| data-bind-attr | Attributes from an object expression | all |
| data-cloak | Hides content until the first render | all |
| Conditionals | ||
| data-show | Shows or hides with CSS | all |
| data-render | Adds or removes from the DOM | all |
| data-transition | CSS enter and leave classes | standard, spa, full |
| Events | ||
| data-action | Calls component methods on events | all |
| data-event-* | Event modifiers: prevent, stop, once, passive, capture, self, outside, debounce, throttle, delay, if | all |
| data-event-key-* | Keyboard filters and combinations | all |
| Forms | ||
| data-model | Two-way form binding | all |
| data-model-trim / -number / -lazy / -event | Value and event modifiers for data-model | all |
| data-validate-on, data-validate, data-validate-message, data-error-for | Form validation and error messages | all |
| Lists and pools | ||
| data-list | Renders an array through a template | mini, lite and above |
| data-key | Row identity for lists and pools | list and pool builds |
| data-template-key + data-type | A template per item type | mini, lite and above |
| data-pool | Explicit-control collection renderer | mini-pool, lite and above |
| data-pool-fps / -static / -cull / -cull-props / -sort | Pool rendering options | mini-pool, lite and above |
| Composition | ||
| data-prop-* | Passes one prop to a child component | all |
| data-props | Passes several props at once | all |
| data-slot / data-slot-container | Projects content into named slots | all |
| data-use-template / data-item-template / data-with | Named templates supplied by an ancestor | all |
| data-template-fallback | Fallback for a template name that is not found | all |
| data-portal | Moves content elsewhere in the document | standard, spa, full |
| data-external | Survives HTML content updates | all |
| State and errors | ||
| data-storage-key / data-auto-save | Persists component state to localStorage | all |
| data-error-fallback | Fallback content when a component errors | all |
| Data, routing and SSR | ||
| data-query, data-expect | Renders a query; dev-only shape check | full |
| data-ssr, data-seed, data-type | Server-rendered components and adopted values | full |
| data-no-router | A link the SPA router leaves alone | spa, full |
| Extending and configuring | ||
| data-{name} | Custom directives registered with wildflower.directive() | all |
| data-debug, data-error-handling, data-auto-init, data-wf-prefix, data-csp-safe | Configuration on the framework's script tag | all |
data-component
Marks an element as a component root and associates it with a component definition.
Syntax
<div data-component="component-name">...</div>
Description
When the framework initializes, it scans for elements with data-component and creates component instances. The attribute value must match a registered component name.
Example
<!-- HTML -->
<div data-component="counter">
<span data-bind="count">0</span>
<button data-action="increment">+</button>
</div>
// JavaScript - must be registered before or after the element exists
wildflower.component('counter', {
state: { count: 0 },
increment() { this.count++; }
});
Notes
- Each element gets a unique
data-component-idautomatically assigned - Components can be nested - child components initialize after parents
- The component name should use kebab-case (e.g.,
user-profile)
data-bind
Binds an element's text content to a state property or computed value.
Syntax
<span data-bind="propertyPath"></span>
<span data-bind="nested.property.path"></span>
<span data-bind="$entityName.path"></span>
Supported Formats
| Format | Description | Example |
|---|---|---|
property |
Bind to state or computed property | data-bind="username" |
nested.path |
Bind to nested property | data-bind="user.address.city" |
$entity.path |
Bind to external entity (store, component, plugin) | data-bind="$user.name" |
Example
wildflower.component('profile', {
state: {
user: { name: 'Alice', role: 'Admin' }
},
computed: {
displayName() {
return `${this.user.name} (${this.user.role})`;
}
}
});
<div data-component="profile">
<p>Name: <span data-bind="user.name"></span></p>
<p>Display: <span data-bind="displayName"></span></p>
</div>
In List Context
Inside a data-list, bindings resolve against the current item:
<ul data-list="users">
<template>
<li>
<span data-bind="name"></span> - <span data-bind="email"></span>
<span data-bind="_index"></span> <!-- Built-in index -->
</li>
</template>
</ul>
data-bind-html
Binds an element's innerHTML to a state property. Use with caution.
Syntax
<div data-bind-html="htmlContent"></div>
Example
wildflower.component('content', {
state: {
markup: '<strong>Bold</strong> and <em>italic</em>'
}
});
<div data-component="content">
<div data-bind-html="markup"></div>
</div>
data-bind-class
Dynamically sets CSS classes based on an expression.
Syntax
<div data-bind-class="expression"></div>
Expression Forms
The expression can produce a string of space-separated class names, an object whose keys are class names and whose values decide whether each class is on, or an array of class names. Classes already written in the element's class attribute are kept; the binding only adds and removes the classes it set itself.
<!-- String: ternary expression -->
<div data-bind-class="isActive ? 'active' : 'inactive'"></div>
<!-- String: multiple classes -->
<div data-bind-class="isError ? 'alert alert-danger' : 'alert alert-success'"></div>
<!-- Object: each class on when its value is truthy -->
<div class="card" data-bind-class="{ 'is-active': isActive, 'is-disabled': !enabled }"></div>
Available Variables
- State properties:
isActive,status,user.role - Computed properties, by name:
isValid(orcomputed:isValid) - In lists: item properties like
done,type, plus_index,_first,_last
Example
wildflower.component('task', {
state: {
tasks: [
{ text: 'Learn WildflowerJS', done: true },
{ text: 'Build something', done: false }
]
}
});
<ul data-list="tasks">
<template>
<li data-bind-class="done ? 'completed text-muted' : ''">
<span data-bind="text"></span>
</li>
</template>
</ul>
data-bind-style
Dynamically sets inline styles based on an expression.
Syntax
<div data-bind-style="expression"></div>
Expression Format
The expression should evaluate to an object with camelCase CSS properties:
<!-- Object literal -->
<div data-bind-style="{ color: textColor, backgroundColor: bgColor }"></div>
<!-- Computed property returning object -->
<div data-bind-style="dynamicStyles"></div>
<!-- With state reference -->
<div data-bind-style="{ width: progress + '%' }"></div>
Example
wildflower.component('progress-bar', {
state: {
progress: 65,
color: '#4CAF50'
},
computed: {
barStyles() {
return {
width: this.progress + '%',
backgroundColor: this.color,
height: '20px',
transition: 'width 0.3s ease'
};
}
}
});
<div data-component="progress-bar">
<div class="progress-track">
<div data-bind-style="barStyles"></div>
</div>
<span data-bind="progress"></span>%
</div>
data-bind-attr
Dynamically sets HTML attributes based on an object expression.
Syntax
<element data-bind-attr="expression">
Description
The expression should evaluate to an object where keys are attribute names and values are attribute values. A value of null or undefined removes the attribute. On boolean HTML attributes such as disabled, checked or hidden, false removes the attribute and true sets it with an empty value. On any other attribute, true and false are written as the strings "true" and "false", which is what aria-* attributes expect. Event-handler attributes such as onclick are never set.
Example
<img data-bind-attr="{ src: avatarUrl, alt: userName, title: userName }">
<!-- Conditional boolean attribute -->
<button data-bind-attr="{ disabled: isSubmitting }">Submit</button>
<!-- In a pool template -->
<div data-pool="items">
<template>
<a data-bind-attr="{ href: url, target: external ? '_blank' : null }"
data-bind="label"></a>
</template>
</div>
data-cloak
Prevents flash of unstyled content (FOUC) during initial render.
Syntax
<div data-component="app" data-cloak>...</div>
Description
Add a CSS rule to hide cloaked elements before the framework initializes. After the first render pass completes (including data-show/data-render evaluation), the framework removes the attribute, making the content visible. This is deferred via requestAnimationFrame so conditionals are evaluated before the cloak is lifted.
Required CSS
[data-cloak] { display: none !important; }
The !important is load-bearing. [data-cloak] has the same specificity as a single class, so any component rule that sets display would win the tie and the element would flash until the framework hides it. With the prefix, the rule is [data-wf-cloak] { display: none !important; }.
Example
<style>[data-cloak] { display: none !important; }</style>
<div data-component="dashboard" data-cloak>
<div data-show="isLoggedIn">Welcome back!</div>
<div data-show="!isLoggedIn">Please log in.</div>
</div>
data-show
Conditionally shows/hides an element using CSS display property.
Syntax
<div data-show="condition">...</div>
<div data-show="!condition">...</div> <!-- Negated -->
Description
When the condition is falsy, the element gets display: none. The element remains in the DOM.
Example
wildflower.component('loader', {
state: {
isLoading: true,
hasError: false,
data: null
}
});
<div data-component="loader">
<div data-show="isLoading">Loading...</div>
<div data-show="hasError">Error occurred!</div>
<div data-show="!isLoading && !hasError">
<span data-bind="data"></span>
</div>
</div>
Computed Conditions
<div data-show="shouldShow">...</div>
data-render
Conditionally adds/removes an element from the DOM entirely.
Syntax
<div data-render="condition">...</div>
Difference from data-show
| Attribute | When False | Use Case |
|---|---|---|
data-show |
Hidden via CSS (display: none) |
Frequent toggling, preserve state |
data-render |
Removed from DOM entirely | Heavy content, conditional components |
Example
<div data-component="app">
<!-- Component only initialized when isLoggedIn is true -->
<div data-render="isLoggedIn">
<div data-component="user-dashboard">...</div>
</div>
<div data-render="!isLoggedIn">
<div data-component="login-form">...</div>
</div>
</div>
data-transition
Applies CSS transitions when an element with data-show or data-render enters or leaves. Standard, spa and full builds.
Syntax
<div data-show="condition" data-transition="transition-name">...</div>
CSS Classes Applied
| Class | When Applied |
|---|---|
{name}-enter | Starting state for enter |
{name}-enter-active | Active/ending state for enter |
{name}-leave | Starting state for leave |
{name}-leave-active | Active/ending state for leave |
The classes come off when the element's CSS transition ends. With no transition duration in the CSS they come off at once, so the CSS is what gives the effect its length.
Example CSS
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 1;
transition: opacity 300ms ease-in;
}
.fade-leave {
opacity: 1;
}
.fade-leave-active {
opacity: 0;
transition: opacity 300ms ease-out;
}
Example HTML
<div data-show="isVisible" data-transition="fade">
This content fades in and out
</div>
See Transitions for JavaScript hooks.
data-action
Binds DOM events to component methods.
Syntax
<!-- Default click event -->
<button data-action="methodName">Click</button>
<!-- Specific event -->
<input data-action="input:onType">
<form data-action="submit:onSubmit">
<!-- Several actions on one element, separated by spaces -->
<input data-action="focus:onFocus blur:onBlur">
<!-- Arguments -->
<button data-action="setFilter('done')">Done</button>
Method Signature
methodName(event, element, context) {
// event - The DOM event object
// element - The element that triggered the event
// context - Additional context (index in lists, etc.)
}
Example
wildflower.component('search', {
state: { query: '', results: [] },
onSearch(event, element) {
this.fetchResults();
},
async fetchResults() {
// ... fetch logic
}
});
<form data-component="search" data-action="submit:onSearch" data-event-prevent>
<input type="text" data-model="query">
<button type="submit">Search</button>
</form>
data-event-*
Modifiers that sit beside data-action on the same element and change how its events are handled.
| Attribute | Effect |
|---|---|
data-event-prevent | Calls event.preventDefault() before the handler runs |
data-event-stop | Calls event.stopPropagation() |
data-event-once | The handler fires at most once, then the listener is removed |
data-event-passive | Registers a passive listener (improves scroll performance) |
data-event-capture | Listens in the capture phase |
data-event-self | Fires only when the event's target is the element itself, not a child |
data-event-outside | Fires on clicks outside the element (for closing menus and popovers) |
data-event-debounce="300" | Waits until events stop for this many milliseconds (default 300) |
data-event-throttle="300" | Runs at most once per this many milliseconds (default 300). If debounce is also set, debounce wins |
data-event-delay="500" | Runs the handler after this many milliseconds, unless the component was destroyed in between |
data-event-if="expression" | Runs the handler only when the expression, evaluated against component state, is truthy |
Example
<input data-action="input:search" data-event-debounce="300">
<div class="menu" data-action="closeMenu" data-event-outside>...</div>
<button data-action="save" data-event-if="isDirty">Save</button>
See Advanced Events for more.
data-event-key-*
Keyboard filters: the action runs only for the listed keys. They apply to keyboard events (keydown, keyup).
Syntax
<!-- One key -->
<input data-action="keydown:submit" data-event-key-enter>
<!-- Any of several keys -->
<input data-action="keydown:close" data-event-key-esc data-event-key-tab>
<!-- A combination, joined with + -->
<div data-action="keydown:save" data-event-key-ctrl+s>...</div>
Keys
- Names match
event.key, lowercased:data-event-key-a,data-event-key-f2. - Aliases:
enter(Enter or Return),escandescape,space,up,down,left,right,tab,deleteandbackspace(each matches both). - A bare
data-event-key-ctrl,-alt,-shiftor-metarequires that modifier on every match. - When several keys or combinations are listed, any one of them matches.
data-model
Creates two-way binding between a form input and state property.
Syntax
<input data-model="propertyPath">
Supported Elements
| Element | Event | Property |
|---|---|---|
<input type="text"> | input | value (string) |
<input type="number">, type="range" | input | value (number; empty stays '') |
<input type="checkbox"> | change | checked (boolean) |
<input type="radio"> | change | value (string) |
<textarea> | input | value (string) |
<select> | change | value (string) |
Example
wildflower.component('form-demo', {
state: {
username: '',
email: '',
subscribe: false,
plan: 'free'
}
});
<div data-component="form-demo">
<input type="text" data-model="username" placeholder="Username">
<input type="email" data-model="email" placeholder="Email">
<label>
<input type="checkbox" data-model="subscribe">
Subscribe to newsletter
</label>
<select data-model="plan">
<option value="free">Free</option>
<option value="pro">Pro</option>
</select>
</div>
data-model-trim / -number / -lazy / -event
Presence attributes that change how data-model writes to state.
| Attribute | Effect |
|---|---|
data-model-trim | Trims whitespace from the value before writing it |
data-model-number | Writes the value as a number (parseFloat). An empty field stays ''; text that is not a number is kept as typed |
data-model-lazy | Writes on change and blur instead of on every keystroke |
data-model-event="evt" | For web components: the event that carries the new value (for example sl-input). The default listens for both input and change |
Example
<input data-model="quantity" data-model-number>
<input data-model="name" data-model-trim data-model-lazy>
<sl-input data-model="email" data-model-event="sl-input"></sl-input>
See Forms and Component Libraries.
data-validate-on, data-validate, data-validate-message, data-error-for
Form validation. The form opts in with data-validate-on; each input is checked with the browser's own constraints (required, type="email", minlength and so on) plus an optional data-validate rule.
| Attribute | On | Effect |
|---|---|---|
data-validate-on="submit" | form | When to validate: a comma list of submit and blur. A failed submit stops the form's data-action from running. A change event always re-validates the changed field |
data-validate="rule" | input | An extra rule: number, integer, or a regular expression written as /pattern/ |
data-validate-message="text" | input | The message for a failed /pattern/ rule |
data-error-for="path" | any element | Shows the error for the input whose data-model is path, and hides when that input is valid |
A field that fails gets the class invalid. The component's state gets formValid and validationErrors. Add novalidate to the form so the browser's own popups stay out of the way.
Example
<form data-validate-on="blur,submit" data-action="submit:register" novalidate>
<input type="email" data-model="email" required>
<span class="error" data-error-for="email"></span>
<input data-model="zip" data-validate="/^\d{5}$/" data-validate-message="Five digits">
<span class="error" data-error-for="zip"></span>
<button type="submit">Register</button>
</form>
See Forms and Advanced Forms.
data-list
Renders a list of items from an array in state. Mini, lite, standard, spa and full builds.
Syntax
<container data-list="arrayPath">
<template>
<!-- Item template -->
</template>
</container>
<!-- From computed property -->
<container data-list="filteredItems">...</container>
Put data-list on an element inside the component, not on the component's root element.
Template Context Variables
| Variable | Type | Description |
|---|---|---|
_index | number | Zero-based index of current item |
_length | number | Total number of items |
_first | boolean | True if first item |
_last | boolean | True if last item |
Example
wildflower.component('todo-list', {
state: {
todos: [
{ id: 1, text: 'Learn WildflowerJS', done: true },
{ id: 2, text: 'Build an app', done: false }
]
},
removeTodo(event, element, context) {
this.todos.splice(context.index, 1);
}
});
<div data-component="todo-list">
<ul data-list="todos" data-key="id">
<template>
<li data-bind-class="done ? 'completed' : ''">
<!-- data-model writes the item's done field; no action needed -->
<input type="checkbox" data-model="done">
<span data-bind="text"></span>
<span class="index">#<span data-bind="_index"></span></span>
<button data-action="removeTodo">Delete</button>
</li>
</template>
</ul>
</div>
data-key
Specifies a unique identifier property for optimized list rendering.
Syntax
<ul data-list="items" data-key="id">...</ul>
Description
When items have unique IDs, the framework can optimize updates by reusing existing DOM elements. Without keys, items are matched by index which can cause issues when reordering.
Auto-Detection
If items have an id property, the framework automatically uses it for keying. Use data-key to specify a different property.
Example
<!-- Using 'id' property (auto-detected if present) -->
<ul data-list="users" data-key="id">...</ul>
<!-- Using custom key property -->
<ul data-list="products" data-key="sku">...</ul>
data-template-key + data-type
Renders each list item with a template chosen by one of its fields. Mini, lite, standard, spa and full builds.
Syntax
<div data-list="messages" data-key="id" data-template-key="kind">
<template data-type="text"><p data-bind="body"></p></template>
<template data-type="image"><img data-bind-attr="{ src: url }"></template>
<template><p>Unsupported message</p></template>
</div>
Each item uses the <template> whose data-type equals the item's kind. A template with no data-type is the default. See Dynamic Templates.
data-pool
Explicit-control collection renderer. Unlike data-list, pool items are plain JS objects with zero reactive proxy overhead. Handles full CRUD, selection, and bulk operations, faster than the reactive path for performance-sensitive workloads, real-time data, and per-frame animation. DOM updates are batched via a shared requestAnimationFrame loop. Mini-pool, lite, standard, spa and full builds.
Syntax
<div data-pool="poolName" data-key="id">
<template>
<!-- Entity template -->
</template>
</div>
Declaration (preferred)
pools: {
enemies: {
onAdd: 'onSpawn', // lifecycle hook (string ref or inline fn)
onRemove: 'onDeath', // fires before individual removal
onClear: 'onWaveEnd' // fires once on bulk clear
},
projectiles: {} // no hooks needed
}
// Access: this.pools.enemies.add({...})
API (container this.pools.name, or this.getPool(name) for any pool)
| Method / Property | Description |
|---|---|
pool.add(obj) | Add an entity to the pool |
pool.remove(key) | Remove entity by key value |
pool.get(key) | Get entity object by key (or undefined) |
pool.clear() | Remove all entities |
pool.items | Raw array of entity objects, mutate properties freely |
pool.size | Current entity count |
pool.getElement(key) | Get DOM element for an entity by key |
pool.markDirty(key) | Mark a single entity for re-render. Switches the pool from animation mode (default: all entities flushed every frame) to targeted mode (only dirty entities are flushed). Use for sparse, data-driven updates where most entities are unchanged between frames. |
Pool Modifier Attributes
| Attribute | Description |
|---|---|
data-pool-fps="N" | Cap render rate to N frames per second. Omit for native frame rate. |
data-pool-static | Boolean (no value): passive pool, skips rAF flush entirely. With a value (data-pool-static="propName"): per-entity static property; entities with a truthy value for that property are excluded from the per-frame flush. |
data-pool-cull="N" | Enable spatial culling. N is padding in pixels around the viewport; entities outside the padded bounds are skipped during flush. |
data-pool-cull-props="x,y" | Data-based culling via entity properties. Accepts "x,y" (point) or "x,y,w,h" (rect): maps entity property names to spatial coordinates for culling decisions. |
data-pool-sort="prop" | Z-index sort by entity property. Use data-pool-sort="prop:desc" for descending order. |
Supported Template Bindings
data-bind, data-bind-style, data-bind-attr, data-bind-class, data-show, and data-action (handled by delegation; the handler receives the entity).
Constraints
- Pool templates can only reference entity properties; component state, computed properties, and store values are NOT available inside pool templates
data-keyspecifies the unique identifier property (defaults toid)- Pools are automatically cleaned up when the owning component is destroyed
Example
<div data-pool="enemies" data-key="id">
<template>
<div class="sprite" data-bind-style="{ left: x + 'px', top: y + 'px' }">
<img data-bind-attr="{ src: imgSrc }">
<span data-bind="label"></span>
</div>
</template>
</div>
wildflower.component('game-board', {
init() {
this.pools.enemies.add({ id: 1, x: 100, y: 200, imgSrc: 'orc.png', label: 'Orc' });
},
gameLoop() {
// Animation mode (default): mutate freely, all entities flush every frame
for (const enemy of this.pools.enemies.items) {
enemy.x += enemy.speed;
}
},
// Targeted mode: call markDirty() for sparse updates (e.g., data dashboards)
updateScore(id, newScore) {
const enemy = this.pools.enemies.get(id);
enemy.score = newScore;
this.pools.enemies.markDirty(id); // only this entity re-renders
}
});
When to Use
Start with data-list; it's the right default. Use data-pool when you need explicit update control, better performance at scale, real-time data, or high-frequency rendering. Use data-list when items need two-way binding (data-model), parent computed properties, or nested lists.
data-prop-*
Passes data from parent to child components via props.
Syntax
<!-- Pass state property -->
<div data-component="child" data-prop-user="currentUser"></div>
<!-- Pass a literal string: quote it -->
<div data-component="child" data-prop-theme="'dark'"></div>
<!-- Text that could not be a state name is also passed as written -->
<div data-component="child" data-prop-title="Hello World"></div>
<!-- Numbers, booleans and null are literals -->
<div data-component="child" data-prop-count="42" data-prop-visible="true"></div>
<!-- Pass parent method as callback -->
<div data-component="child" data-prop-on-save="handleSave"></div>
How values resolve
true,false,null, numbers, and anything in single or double quotes are literals.- Otherwise the value is looked up in the parent: a
$entity.path, a state path, a computed property, then a parent method (passed bound to the parent). - A value that looks like a name but finds nothing (
data-prop-theme="dark"with nodarkin the parent) givesundefined, so the prop's default applies and development builds warn. Quote it to pass the word itself. - A value that could not be a name, such as
Hello World, is passed as the literal text.
Description
Props provide explicit data flow from parent to child components. The attribute name after data-prop- becomes the prop name in camelCase (e.g., data-prop-user-name becomes userName).
Example
// Child component defines expected props
wildflower.component('user-card', {
props: {
user: { type: Object, required: true },
theme: { type: String, default: 'light' }
},
computed: {
displayName() {
return this.props.user.name;
}
}
});
<div data-component="parent">
<div data-component="user-card"
data-prop-user="currentUser"
data-prop-theme="'dark'">
<span data-bind="props.user.name"></span>
</div>
</div>
Notes
- Props are accessed via
this.propsin JavaScript andprops.*in bindings - Props are reactive - child updates when parent data changes
- See Props Guide for type validation and defaults
data-props
Passes multiple props to a child component in a single attribute using object expression syntax.
Syntax
<!-- Values resolve from parent state -->
<div data-component="child" data-props="{ title: cardTitle, color: accentColor }"></div>
<!-- Quoted string values (commas allowed inside quotes) -->
<div data-component="child" data-props="{ label: 'hello, world', color: color }"></div>
Description
A convenience syntax for passing multiple props at once instead of using separate data-prop-* attributes. Keys become prop names; values are resolved as parent state paths (or as literal strings when quoted).
Example
<!-- These two are equivalent -->
<div data-component="card"
data-props="{ title: cardTitle, color: accentColor }"></div>
<div data-component="card"
data-prop-title="cardTitle"
data-prop-color="accentColor"></div>
Notes
- Values update reactively when the parent state changes
- Can be used alongside individual
data-prop-*attributes; individual attributes take precedence - See Props Guide for full details
data-slot / data-slot-container
Places marked content into named insertion points inside the same component.
Syntax
<div data-component="card">
<div data-slot-container="slotName"></div> <!-- where it goes -->
<div data-slot="slotName">Content</div> <!-- what goes there -->
</div>
Description
When the component initializes, each data-slot-container in it is emptied and receives the first element in the same component whose data-slot has the same name. Both sit inside the one component element: the containers usually come from the component's markup and the slot content from the page that uses it.
Example
<div data-component="card">
<div class="card-header" data-slot-container="header"></div>
<div class="card-body" data-slot-container="body"></div>
<div data-slot="header"><h3>Card Title</h3></div>
<div data-slot="body"><p>Card content goes here.</p></div>
</div>
See Slots.
data-use-template
References a named template defined by an ancestor component for rendering.
Syntax
<!-- Child references an ancestor's named template -->
<div data-use-template="templateName" data-with="dataPath"></div>
<!-- Only look in one named ancestor component -->
<div data-use-template="templateName@componentName" data-with="dataPath"></div>
Related Attributes
| Attribute | Description |
|---|---|
data-item-template="name" |
An ancestor defines a named template |
data-use-template="name" |
Uses the template; name@component limits the search to that ancestor. Also works as a list's template |
data-with="path" |
Binds the template to a state path (not used inside a data-list, where each row binds to its item) |
data-template-fallback="name" |
A template in the same container used when name is not found |
When the name is not found, the framework uses the content written inside the data-use-template element, then a data-template-fallback template with the same name.
Example
<!-- Parent defines how user should be displayed -->
<div data-component="user-page">
<template data-item-template="userCard">
<div class="card">
<h5 data-bind="name"></h5>
<p data-bind="email"></p>
</div>
</template>
<!-- Child uses the template with its data -->
<div data-component="profile">
<div data-use-template="userCard" data-with="user"></div>
</div>
</div>
Notes
- Enables inversion of control - parent controls presentation, child provides data
- Templates are fully reactive to data changes
- See Configurable Templates Guide for advanced usage
data-item-template
Defines a named template that descendant components can reference.
Syntax
<template data-item-template="templateName">
<!-- Template content with data-bind attributes -->
</template>
See data-use-template for complete usage.
data-portal
Moves an element's content to another place in the document, such as the end of <body> for modals and tooltips. The content keeps its bindings and actions. Standard, spa and full builds.
Syntax
<!-- The value is a CSS selector for the destination -->
<div data-portal="#modal-root" data-show="isOpen">
Modal content here
</div>
<!-- Empty, or "body", means document.body -->
<div data-portal>...</div>
Description
- The element's children move into the first element matching the selector. The element itself stays where it is.
- With
data-showordata-renderon the portal element, nothing moves while the condition is false. When it turns false again,data-showbrings the content back hidden anddata-renderremoves it. - If no element matches the selector, a warning is logged and nothing moves.
- Portal content is cleaned up with its component.
Example
<div data-component="modal-demo">
<button data-action="openModal">Open Modal</button>
<div data-portal="#modal-root" data-show="isModalOpen">
<div class="modal-backdrop">
<div class="modal-content">
<h2>Modal Title</h2>
<p>Modal body content</p>
<button data-action="closeModal">Close</button>
</div>
</div>
</div>
</div>
<!-- Typically at the end of body -->
<div id="modal-root"></div>
See Portals.
data-external
Preserves an element and its component during HTML content updates.
Syntax
<div data-external data-component="live-chart">...</div>
Description
When parent content is updated via data-bind-html or programmatic innerHTML changes, elements marked with data-external are preserved rather than destroyed and recreated. This is useful for:
- Interactive components that maintain internal state (charts, editors)
- Components with expensive initialization
- Live code examples in documentation
Example
<div data-component="content-page">
<!-- This content may be updated dynamically -->
<div data-bind-html="pageContent">
<!-- This chart component survives content updates -->
<div data-external data-component="live-chart">
<canvas id="myChart"></canvas>
</div>
</div>
</div>
Notes
- The element must have a stable position - use placeholder markers if needed
- Works with both components and regular elements
- Garbage collection skips elements marked as external
data-storage-key / data-auto-save
Persists a component's state in localStorage. Both go on the component's root element.
| Attribute | Effect |
|---|---|
data-storage-key="key" | Before init(), loads the saved state stored under key over the declared state. Saving is then up to you: this.saveToStorage() (and this.loadFromStorage() to reload) |
data-auto-save | With a storage key, saves the whole state after every change |
Example
<div data-component="settings" data-storage-key="app-settings" data-auto-save>
<input type="checkbox" data-model="darkMode"> Dark mode
</div>
See Data Attributes.
data-error-fallback
What a component shows when it throws an error that no onError handler deals with. Goes on the component's root element.
Syntax
<!-- A selector for an element inside the component -->
<div data-component="widget" data-error-fallback=".error-message">
<div class="content">...</div>
<div class="error-message" style="display:none">Something went wrong.</div>
</div>
<!-- Or the id of a <template> anywhere in the document -->
<div data-component="widget" data-error-fallback="#widget-error">...</div>
With a selector, the component's other children are hidden and the matching element is shown. With the #id of a <template>, the component's content is replaced by the template's content, and the original is kept so the component can be reset. See Error Boundaries.
data-query, data-expect
Renders a query declared with wildflower.query(). Full builds.
Syntax
<!-- With a <template> child: one row per result -->
<ul data-query="articles">
<template><li data-bind="title"></li></template>
</ul>
<!-- Without one: a single record -->
<div data-query="profile"><h2 data-bind="name"></h2></div>
A data-query element must be inside a component. data-expect="id:number, title:string" on the same element makes development builds warn when incoming rows drift from that shape; production builds ignore it. See Data Query and Shapes.
data-ssr, data-seed, data-type
Attributes for server-rendered markup. Full builds.
| Attribute | Effect |
|---|---|
data-ssr="true" | On a component root: the server-rendered DOM is adopted as the component's content and state, then made live |
data-seed='{"key": value}' | JSON with extra state that is not shown in the markup, merged into the adopted state or rows |
data-type="number" | On a bound element being adopted: reads its text as a number. Also boolean, and json for SSR component state |
See Server-Side Rendering and Queries with SSR.
data-no-router
On a link, tells the SPA router not to handle it, so the browser follows it normally. Spa and full builds.
<a href="/downloads/report.pdf" data-no-router>Report</a>
External links, links with a target other than _self, download links, and clicks with a modifier key are already left alone. See Routing.
data-{name}: custom directives
An attribute of your own, registered with wildflower.directive(). Its value is a state path.
wildflower.directive('tooltip', {
init(el, value, context) { /* context.resolvedValue is the value at the path */ },
update(el, newValue, oldValue, context) { /* runs when the value changes */ },
destroy(el, context) { /* clean up */ }
});
<button data-tooltip="helpText">?</button>
Directive names cannot start with wf-: data-wf-tooltip is the prefixed form of tooltip. See Plugins and Directives.
Script-tag attributes
Configuration read from the <script> tag that loads WildflowerJS. These keep their plain names.
| Attribute | Values | Default |
|---|---|---|
data-debug | Present or "true": debug on. Any other value: off | On in development builds, off in .min builds |
data-error-handling | log, throw or silent | log |
data-auto-init | "false" stops the automatic start; anything else leaves it on | On |
data-wf-prefix | "true" turns on exclusive mode (only data-wf-* attributes are read). A bare attribute does not | Off |
data-csp-safe | Present or "true": always use the CSP-safe expression evaluator | Off (chosen automatically when the page's CSP forbids eval) |
<script src="wildflower.min.js" data-wf-prefix="true" data-error-handling="throw"></script>
See Configuration.