WildflowerJS Demos
htmx + WildflowerJS: MutationObserver auto-init, hx-boost, attribute coexistence

htmx handles the server. This handles the state.

htmx swaps HTML fragments in from the server on its own schedule. Below, every swapped-in fragment contains a live WildflowerJS component. The verification log at the bottom records, in real time, whether the claims below actually hold — not a staged result.

1. Swap in a stateful island

Click to fetch fragments/order-form.html and swap it into the empty slot below (a deliberately slow 150ms swap + 150ms settle, to give any timing race the best chance of showing up). The form has real client-side state: a computed total, and a submit button that carries both an hx-get attribute (htmx's) and a data-bind-attr attribute (WildflowerJS's) on the same element.

2. Boosted navigation

hx-boost intercepts this link, fetches the target page, and swaps the <body> in place instead of a full page load. The target page has its own WildflowerJS component that has never existed on this page before.

Boost to a second page →

Verification

pendingSwapped-in component auto-initializes (no wildflower.scan() call anywhere in this demo)
pendingNo double-init / no race against htmx's settle delay
pendinghx-get and data-bind-attr coexist on one element
pendingComponent on a boosted page auto-initializes

Event log

HTML

<button hx-get="fragments/order-form.html"
        hx-target="#order-slot"
        hx-swap="innerHTML">
    Load order form
</button>
<div id="order-slot"></div>

<!-- fragments/order-form.html -->
<div data-component="order-form">
    <input data-model="qty">
    <input data-model="price">
    <span data-bind="total"></span>
    <button data-bind-attr="{ disabled: overBudget }"
            hx-get="fragments/confirmation.html"
            hx-target="#order-slot">
        Place order
    </button>
</div>

JavaScript

// Registered once, up front. htmx swaps markup; it never needs to know
// this component exists. WildflowerJS's mutation observer does the rest.
wildflower.component('order-form', {
    state: { qty: 2, price: 15, budget: 100 },
    computed: {
        total() { return this.qty * this.price; },
        overBudget() { return this.total > this.budget; }
    }
});