WildflowerJS 1.1 is out! Browser DevTools, jQuery coexistence, item-level computed properties in every binding type, a smaller build for apps that don't need pools, and a build pipeline that runs zero npm install. Performance gains in the 2.7–6x range for cross-store rendering. Two breaking changes, both with one-line migrations.
Upgrading from v1.0? Two attribute renames. Action handlers no longer stop event propagation by default. If you relied on that, add data-event-stop to the affected element. data-model-debounce is gone. Migrate to data-event-debounce on the same element with a paired action. Details in the breaking-changes section below.
DevTools
WildflowerJS now exposes window.__WF_DEVTOOLS_GLOBAL_HOOK__ for runtime introspection, and v1.1 ships with two ways to consume it:
- A standalone
@wildflowerjs/devtoolsdrop-in script you can include in any app for a built-in debugging panel. - An MV3 browser extension for Chrome and Firefox, headed for the official extension stores.
Both surface the same panels:
- Components: live tree of mounted components with their state, computed values, props, and the stores they subscribe to. State and store values are editable in place for quick what-if poking.
- Stores: every registered store with its current state and the methods it exposes.
- Pools: pool name, owning component, current entity count, recycle-pool size, and target FPS for tick scheduling. Useful for catching pool-leak regressions before they hurt.
- Bindings: every active binding on the page by type (
data-bind,data-bind-html,data-show,data-model,data-list,data-pool) with the path it's bound to and which component owns it. - Routes: current route, full route tree, navigation state, guard counts.
The hook also emits lifecycle events (componentInit, componentDestroy, store-ready, routeChange) so third-party integrations can subscribe to framework activity without monkey-patching.
Build pipeline now runs no npm install
This one might be the most distinctive thing about v1.1. The framework distribution itself has always had no runtime dependencies. As of v1.1, the process that builds the framework also has no install-time dependencies. The whole pipeline runs on three SHA-512-pinned tarballs (rollup, terser, acorn) fetched and verified on first build, then reused. There is no npm install, transitive dependency tree, postinstall script, or lock file to audit.
The relevance is uncomfortably current. Seven days before this release, on May 11, 2026, the Mini Shai-Hulud worm compromised 170+ npm packages in a 6-minute window - the entire @tanstack ecosystem, Mistral AI's SDK, UiPath's automation suite (65 packages), OpenSearch (1.3M weekly downloads). OpenAI was among the named affected companies. The malicious versions were attested at SLSA Build Level 3: the cryptographic "safe-to-trust" signal didn't help, because the signal came from the same GitHub Actions infrastructure the worm had already compromised.
Framework users who consume WildflowerJS via <script> tag or npm install wildflowerjs have always been immune-by-construction to this entire class of attack: WF has no transitive npm dependency tree to compromise, no postinstall hooks to hijack. With v1.1, the framework's own build pipeline now matches that posture. Three SHA-512-pinned tarballs, with no npm install and no GitHub-Actions trust boundary for an attacker to exploit. Anyone auditing WildflowerJS for use in security-sensitive contexts can verify the entire build with three tarball hashes.
Output bundles are identical to the previous rollup pipeline, and are still subject to and passing the full Vite/Chromium test suite across all 15 build variants.
Performance
Two changes worth calling out:
- Cross-store computed cache-hit fast path: if your app reads from multiple stores in components, this is the headline win. End-to-end render speedups of 2.7–6x in read-heavy cross-store scenarios. The fast path skips redundant graph traversal when a computed's dependencies haven't changed.
- Batch change-detection rebuild around the proxy: brings improvements to the krausest benchmark suite, and let us delete around 600 lines of legacy diff code in the process. Smaller surface area, faster updates.
Pools
Pools now accept an entity block, bringing them in line with the shape components, stores, and plugins already use:
wildflower.component('dust', {
pools: {
particles: {
entity: {
state: { x: 0, y: 0 },
computed: { faded() { return this.x > 800; } },
methods: { wrap() { this.x %= 800; } }
}
}
}
});
If you've worked in any other part of the framework, the entity block will be immediately familiar. state, computed, and methods behave the same way they do in components and stores. The unification continues a theme: one mental model across every reactive surface.
Pools also gained array-like methods and properties: push, pop, length, at(i), find, filter, map, forEach, some, every, reduce, and Symbol.iterator, layered on top of the existing add / remove / size APIs. There is no splice, indexOf, or slice. Pools use swap-with-last removal, so positional indices are not stable across mutations. Use remove(key) for keyed removal and at(i) for DOM-ordered positional reads.
Finally, pools now support pool-level props: shared, reactive state on the pool itself. The owning component can read and update props at any time, and every entity's methods and computeds see the current value without it being duplicated per-entity.
jQuery coexistence
WildflowerJS now coexists cleanly with jQuery on the same page. v1.1 ships with 34 tests across jQuery 4.0.0 (which WordPress core now ships) and jQuery 3.7.1 (still common in legacy WordPress installs) covering event-handler interaction, DOM mutation overlap, AJAX flows, and the surprises that show up when both frameworks try to listen on the same element.
The headline interaction is event handling. In v1.0, action handlers stopped event propagation by default, which silently swallowed events that jQuery's $(document).on(…) delegation expected to receive. v1.1 lets events bubble naturally past action handlers (see Breaking Changes below), which restores the cooperative behavior most apps expect.
If your app sits inside a WordPress theme, a Drupal site, a Shopify page, or anywhere else jQuery-style delegation is already in play, v1.1 should slot in without a fight.
Item-level computed properties in every binding type
This one surfaced when we tried using Claude Design (the new AI prototyping tool) to build a UI from nothing but the WildflowerJS website's llms.txt and the AI-assistant page. Claude kept reaching for item-level computed properties inside list bindings ("show this row in red if the item is overdue," for example), and v1.0 silently evaluated those references as undefined rather than erroring, leading to hacky workarounds and (warranted) complaints from the AI.
v1.1 supports item-level computed properties in every binding type: data-bind, data-bind-class, data-bind-style, data-bind-attr, data-show, and data-render. Inside a list, the binding expression sees both the item's own state and any computed properties defined on the item shape, with the same precedence rules as component-level bindings.
This is a feature most reactive frameworks have, and now so does WildflowerJS.
New mini build variant
v1.1 adds a fifth build variant: mini. It's the lite build minus the pools subsystem, for apps that don't use high-throughput rendering and want a smaller bundle.
The full lineup is now mini → lite → core → spa → full, with mini at the smallest end and full at the largest. Each variant ships in dev, raw, and minified flavors with brotli + gzip pre-compression.
Breaking changes
Two breaking changes, both with one-line migrations.
Action handlers no longer stop event propagation by default
In v1.0, click events (and other events dispatched via data-action) had their propagation stopped after the action ran. This silently consumed events that external delegation systems (jQuery, vanilla event delegation, third-party widgets) expected to receive on the document.
In v1.1, events bubble naturally past the action handler. Internal nested-component double-fire is still prevented via a per-event marker, without relying on stopPropagation. Most apps will see no behavioral change.
If you specifically relied on action handlers stopping the bubble chain (modal click-outside guards, dropdown dismissal logic, anywhere you'd otherwise call event.stopPropagation()), add data-event-stop to the element to opt back in to the v1.0 behavior on that element only:
<button data-action="open" data-event-stop>Open menu</button>
The data-model-debounce attribute is removed
Debouncing belongs on the action that receives the input, not on the model binding. The v1.0 attribute's semantics collided with list re-render timing and produced occasional stale-value hazards.
Migrate data-model-debounce="300" to data-action="input:handleInput" paired with data-event-debounce="300" on the same element:
<!-- v1.0 -->
<input data-model="query" data-model-debounce="300">
<!-- v1.1 -->
<input data-model="query" data-action="input:handleInput" data-event-debounce="300">
The action layer is the right place for debouncing because it sits at the boundary where user intent enters the system, and it composes cleanly with the rest of the event-handling pipeline.
Security
v1.1 closes the single exploitable finding from a recent security audit, plus a related hardening:
xlink:hrefis now in the URL-attribute sanitizer. Previously, an attacker-controlled value bound toxlink:hrefon an SVG<a>or<use>could carry ajavascript:URI past the existing checks.- The
data:image/allowlist is narrowed to raster formats only.data:image/svg+xmlis no longer permitted, since inline SVG can carry scripted content.
A 16-test regression suite has been added to lock both fixes in place.
Better dev-mode error messages
Every WF-NNN warning in dev mode now prints a clickable docs link pointing at the canonical fix recipe, along with suggestion text where the framework can pin down the right next move. Several scattered [WF-XXX] console calls were also migrated through the unified error path so all warnings get the same treatment. Example for the new data-bind-class shape warning:
[WF WF-505] Class binding shape mismatch (coerced): computed returned an object; coercing truthy keys to a class string
↳ Suggestion: A computed should return a string. For inline expressions, write `data-bind-class="{'is-active': cond}"`.
↳ Docs: https://www.wildflowerjs.com/docs/error-codes?code=WF-505
Notable fixes
- Memory leak on
destroyComponent: effects scoped to internal RSM stub instances were leaking past component teardown. The destroy path now sweeps them along with the rest of the component's effect set. - List actions shadowed by ancestor
data-action: when an ancestor element carried adata-actionand the row's own action was stripped at scan time, the click would route to the ancestor instead of the row. Click delegation now falls through to the row's metadata. - Item-level computeds reacting to external store mutations: computeds defined on a list-item shape now invalidate correctly when the data they read from a store changes.
- Nested
data-listhydration timing: inner lists rendered before the outer store had hydrated would render empty. They now wait for hydration and render correctly on the next flush. - Portal binding performance:
_renderPortalBindingsnow uses a per-component context index instead of a full traversal, removing a hot-path bottleneck at high portal counts. - Validation false-positives: the binding-expression validator no longer flags legitimate property accesses (e.g.
state.foo.bar) as undefined state references. - Same-name field/computed leak in list bindings: when an item field and a component-level computed shared the same name inside a list (e.g. a component had a
teamColorcomputed, and each row in a sub-list also had ateamColorfield), the component-level computed was winning the lookup and overwriting per-row values across rows. Per-row item fields now take precedence as documented. Affectsdata-bind-styleanddata-bind-classwith object syntax. - In-list effect race with component-level writers: component-level object/class-binding effects were registering against elements inside
data-listrows, racing with the list's own per-row writers and producing intermittent visual glitches. Effect registration now skips in-list elements; per-row updates own those elements exclusively. - Internal: a documented lifecycle invariant set and a 15-scenario race harness are now part of the regression suite, locking the framework's init/destroy contract against future drift.
Try it
Install via npm:
npm install wildflowerjs@1.1
Or drop in via CDN:
<script src="https://cdn.jsdelivr.net/npm/wildflowerjs@1/dist/wildflower.lite.min.js"></script>
→ Installation guide
→ Documentation
→ GitHub
WildflowerJS reaches new developers exactly one way: someone who tried it tells someone else. If you checked out WildflowerJS and find it interesting, please pass on a link to friends. Thanks!