Composition Patterns All

A short map of how WildflowerJS apps fit together. There are four kinds of composition, each backed by a small set of concrete features. Use this page to pick which feature you want, then click through to its implementation docs for the details.

Why a separate page for this? Most framework docs jump straight into APIs. Knowing the four kinds of composition first makes the rest of the docs faster to navigate, because every feature you'll meet is a concrete instance of one of them.

The Four Kinds

Kind Mechanism Use it for
Structural <template> + data-use-template Reusing visual fragments across components. A child slots a piece of UI from its parent.
Logic wildflower.component + wildflower.store Owning state and behaviour. Components own UI logic; stores own cross-component or cross-page data.
Action data-action delegation Connecting parent UI to child methods (or vice versa) without prop drilling. Click handlers find their owner by walking up the DOM.
Temporal SSR hydration + lazy template resolution Composing the app over time as scripts and templates arrive. New components register; existing ones rescan; nothing pre-loads.

Structural Composition

A child component asks its parent for a template by name. The parent (or any ancestor) provides the markup; the child instantiates it and binds its own state. The same child renders differently in different parents, with no JavaScript change.

<!-- Parent provides the template -->
<div data-component="dashboard">
    <template data-item-template="userCard">
        <div class="card">
            <h3 data-bind="name"></h3>
            <p data-bind="role"></p>
        </div>
    </template>

    <!-- Child consumes it -->
    <div data-component="user-list">
        <div data-list="users" data-key="id">
            <template data-use-template="userCard"></template>
        </div>
    </div>
</div>

Resolution walks up the DOM tree from the child. The closest ancestor with a matching template wins. To target a specific component instead of "closest," use data-use-template="userCard@dashboard".

When to reach for it: a child component's visual shape depends on context. Same logic, different look in different parents. Read more in Configurable Templates and Advanced Configurable Templates.

What it is not: data-driven variants on a single child instance. For "render a different template based on a state value," see Dynamic Templates (data-template-key).

Logic Composition

There are two primitives, picked by lifespan and scope.

Components

A component owns the state and behaviour for a chunk of UI. Lifecycle is tied to its DOM element: created when the element is inserted, destroyed when the element is removed. State on a component is private to that instance.

wildflower.component('counter', {
    state: { count: 0 },
    increment() { this.count++; }
});

Stores

A store owns state that must survive after any single component is destroyed, or be shared across components, or persist across route changes. Stores are global by name and live for the lifetime of the application.

wildflower.store('cart', {
    state: { items: [] },
    add(product) { this.items.push(product); },
    computed: {
        total() { return this.items.reduce((s, i) => s + i.price, 0); }
    }
});

wildflower.component('header', {
    subscribe: ['cart'],
    // this.stores.cart.total reactively updates
});

When to reach for which: default to a component. Reach for a store when two or more components need the same state, or when state must survive a route change. Read more in Basic Stores and Advanced Stores.

Action Composition

An event handler attached with data-action finds its owning component by walking up the DOM. The button doesn't need to know which component it belongs to; the framework figures it out at click time.

<div data-component="todo-list">
    <ul data-list="items" data-key="id">
        <template>
            <li>
                <span data-bind="title"></span>
                <!-- This button's click bubbles up to todo-list.removeItem -->
                <button data-action="removeItem">✕</button>
            </li>
        </template>
    </ul>
</div>
wildflower.component('todo-list', {
    state: { items: [{ id: 1, title: 'Write docs' }] },
    removeItem(event, element, details) {
        // details.index identifies which item the click came from
        this.items.splice(details.index, 1);
    }
});

The same delegation works across nested components: a button inside a child component can target a method on a grandparent if no closer ancestor handles it. This is how parents "skin" children without coupling: the parent provides the template (Structural Composition), and the actions inside that template still resolve to the parent's methods.

When to reach for it: any time a UI fragment needs to invoke logic owned by something further up the tree. Read more in Event Handling.

Temporal Composition

The framework follows the DOM. Components and templates can register at any time; nothing pre-resolves at startup.

Hydration: claim and adopt

Server-rendered HTML carries state inline (input value attributes, bound text nodes, list items already populated). On the client, the framework scans for data-ssr markers, parses state out of the live DOM, attaches reactivity to the existing nodes, and only renders fresh content where SSR didn't reach. No double-render. No flicker. Read more in Server-Side Rendering.

Lazy template resolution

A child component's data-use-template lookup runs at first-render time, not at scan time. As long as the parent's template is in the DOM by the moment the child renders, resolution succeeds. Templates added later can be picked up explicitly via wildflower.rescanItemTemplates(componentId).

Inline fallback content

If a referenced template hasn't loaded yet (or never will), the framework falls back to inline content placed inside the data-use-template element. That is the soft failure mode for asynchronous code splitting.

<div data-use-template="fancyCard" data-with="item">
    <!-- Fallback if fancyCard isn't registered yet -->
    <div><span data-bind="item.title"></span></div>
</div>

When to reach for it: mostly automatic. The patterns matter when you ship a multi-file app where templates and components arrive out of order. Read more in Configurable Templates and SSR.

Three Principles That Follow

The four kinds compose into three working principles.

The DOM is the source of truth. Hydration reads state from rendered HTML. Template resolution walks the live DOM. Action delegation finds owners by ancestor lookup. There is no parallel virtual tree the framework consults; the document is the database.
Parents supply the markup. A child component declares which template it needs by name; the parent provides the markup. Children supply behaviour, parents supply shape. The same child component renders three different ways across three different parents with no JavaScript change.
Animation, persistence, and side concerns are pluggable. The framework provides hooks (lifecycle, transitions, watchers); user code or third-party libraries provide the engines. List item animations use AutoAnimate via dynamic import(). Persistence is opt-in inside store methods. Bundle size scales with what you actually use.

Where to Go Next