WildflowerJS Demos
jQuery Integration Lab
Coexistence, not migration

jQuery + WildflowerJS Coexistence Lab

You have a legacy site running jQuery. You want reactivity without ripping anything out. Drop in Wildflower, keep your jQuery code, and they share the same DOM peacefully. The three zones below are live proofs.

jQuery 4.0 Wildflower 1.1 No bundler No wrappers
Live Console

Event log (jQuery, Wildflower, DOM mutations)

This console is itself a Wildflower component reading entries from a store. When jQuery handlers call wildflower.getStore('demoLog').add(...), the list re-renders reactively. No bridge code, no event bus.

output
Nothing logged yet. Interact with a zone below.
Zone 1

Event Bubbling Lab

jQuery binds .on('click') to the orange outer panel. Wildflower binds data-action to the inner buttons. Click each button and watch the log.

jQuery zone: listening for click bubbling up
Wildflower zone: only the buttons have data-action handlers; clicks on wrapper instead bubble to jQuery

Default jQuery + WF both fire  ·  With data-event-stop only WF fires

Why this matters. In v1.1, Wildflower lets DOM events bubble naturally, so existing jQuery delegation keeps working. When you genuinely want to swallow an event, opt in with data-event-stop.

HTML
<div id="bubble-outer">
    <!-- jQuery handler attached in app.js: -->
    <!-- $('#bubble-outer').on('click', () => demoLog.add('jQuery', 'outer click')); -->

    <button data-action="defaultClick">Click me (default)</button>
    <button data-action="stoppedClick" data-event-stop>Click me (data-event-stop)</button>
</div>
Zone 2

DOM Stress Test

jQuery moves, fades, and wraps Wildflower-managed elements. Data bindings survive every mutation. The count field on each row updates in place wherever jQuery has dragged the row to.

The honest caveat. Like Vue, React, and Svelte, Wildflower delegates list-item click handlers to the list parent. If jQuery's .appendTo() moves a row out of its data-list parent without updating state, the per-item +1 button stops firing on that orphaned row; the click never reaches a delegated handler. Top-level bindings (data-bind="count") still update because they're tracked by element reference, not DOM position; Bump all proves it.

The fix: bridge pattern. Drive the move from state, not from the DOM. The jQuery: relocate to second list button shifts the first item from items into relocatedItems. Wildflower re-renders both lists; the relocated row lives in #stress-relocation-target, which has its own data-list and its own delegated click handler, so the +1 button keeps working. The Kanban demo uses this pattern with SortableJS: the library moves DOM during a drag, the onEnd callback updates the store, Wildflower replays the move, click handlers work everywhere.

jQuery DOM mutations vs. state-driven decoration. Wildflower treats each data-list as its own scope: a cross-list state move destroys the source element and creates fresh from the template at the destination. So jQuery DOM mutations (.wrap(), .addClass(), inline styles) applied to elements between renders won't survive a cross-list move; there's no reactive hook for WF to know about them. For decoration that needs to survive moves, drive it from state. The Decorate (state-driven) button toggles a decorated property on each item; the template binds it via data-bind-class="{ 'jq-decorated': decorated }". The class is part of the reactive contract now. WF applies it on every render, including freshly-created elements at a destination list.

What each button does
// [Bump all (state mutation)]
// State mutation reaches every row regardless of where jQuery has put it:
this.items.forEach(it => it.count++);
this.relocatedItems.forEach(it => it.count++);

// [jQuery: relocate to second list]
// Bridge pattern: drive the move from state. WF re-renders the row into
// #stress-relocation-target's own data-list, where its +1 button works.
// If the moving row happens to be wrapped in foreign DOM, unwrap that one
// row first so its wrapper doesn't strand as an empty div in the source
// list. Other wrapped rows are left alone:
const moved = this.items[0];
const $movedEl = $('#stress-list-host .item').first();
if ($movedEl.parent('.jquery-wrapper').length) $movedEl.unwrap();
this.items.shift();
this.relocatedItems.push(moved);

// [jQuery: hide().fadeIn()]
// Run a jQuery animation across all items. Display flips, listeners survive:
$('#stress-list-host .item, #stress-relocation-target .item').hide().fadeIn(450);

// [jQuery: .wrap()]
// Wrap adds a foreign parent div WF doesn't track. The moving row's
// wrapper is scrubbed inside jqRelocate (above); wrappers on rows that
// don't move stay intact:
$('#stress-list-host .item, #stress-relocation-target .item')
    .wrap('<div class="jquery-wrapper"></div>');

// [Decorate (state-driven)]
// State-driven decoration: class is part of the reactive contract, so WF
// applies it on every render including freshly-created elements after a move:
//
//   template:  <div class="item" data-bind-class="{ 'jq-decorated': decorated }">
//   action:    this.items.forEach(it => it.decorated = true);
//              this.relocatedItems.forEach(it => it.decorated = true);

// [(not a button, illustrative anti-pattern)]
// Don't expect jQuery DOM mutation to survive a cross-list move. WF creates a
// fresh element at the destination from the template and there's no reactive
// hook for it to reapply this class:
$('#stress-list-host .item, #stress-relocation-target .item').addClass('jq-decorated');
Zone 3

Zero-Build Boilerplate

No npm. No webpack. No JSX, no SFC, no virtual DOM. Two script tags, one HTML file. Save the snippet below as test.html, open it in a browser, done.

test.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>jQuery + WildflowerJS</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/wildflowerjs@1/dist/wildflower.mini.min.js"></script>
</head>
<body>

  <div data-component="hello">
    <h1 data-bind="msg"></h1>
    <button data-action="shout">Shout</button>
  </div>

  <script>
    // Wildflower-side: reactive component
    wildflower.component('hello', {
      state: { msg: 'Hello' },
      shout() { this.msg = this.msg.toUpperCase() + '!'; }
    });

    // jQuery-side: same DOM, no wrapper plugins, no bridge
    $(function () {
      $('h1').css('color', '#5fa6a6');
    });
  </script>

</body>
</html>

Wildflower is the reactivity engine. jQuery is the legacy you don't have to delete. Use both, on the same page, on the same elements. BFFs.