Hyper · htmx-style

Boost & out-of-band swaps

One response, many updates: the main content goes to the target, and anything marked kj-swap-oob replaces the element with the same id elsewhere on the page.

kj-boost

Put kj-boost="true" on a container and its links and forms become AJAX requests that swap into body (or the inherited kj-target) and push the URL to history. Without JavaScript they still work as normal links — progressive enhancement for free.

Out-of-band swaps

Any top-level element in a response with kj-swap-oob="true" is pulled out and swapped into the element with the same id. Use a swap style (kj-swap-oob="beforeend:#log") to append instead of replace. kj-select-oob does the same from the requesting side, and $.hyper.oob(html) runs it from JavaScript.

Live · Add to cart — the badge updates out of band

Cart 0

    The response is one line item plus two out-of-band elements.

    View the source for this demo
    HTML
    <div class="row">
      <button kj-post="/api/oob.php" kj-vals='js:{ item: "mug", n: +document.getElementById("oob-count").textContent }' kj-target="#oob-cart" kj-swap="beforeend">Add mug</button>
      <button kj-post="/api/oob.php" kj-vals='js:{ item: "tee", n: +document.getElementById("oob-count").textContent }' kj-target="#oob-cart" kj-swap="beforeend">Add tee</button>
      <button kj-post="/api/oob.php" kj-vals='js:{ item: "cap", n: +document.getElementById("oob-count").textContent }' kj-target="#oob-cart" kj-swap="beforeend">Add cap</button>
      <span>Cart <span id="oob-count" class="badge">0</span></span>
    </div>
    <ul id="oob-cart" class="oob-cart" aria-live="polite"></ul>
    <p id="oob-status" class="muted">The response is one line item plus two out-of-band elements.</p>

    Live · Boosted links (without history, for the demo)

    Plain links — boosted into AJAX. Without JavaScript they would simply navigate.

    View the source for this demo
    HTML
    <nav class="row" kj-boost="true" kj-target="#bo-panel" kj-push-url="false" aria-label="Boosted tabs">
      <a class="btn" href="/api/tab.php?tab=core">Core</a>
      <a class="btn" href="/api/tab.php?tab=hyper">Hyper</a>
      <a class="btn" href="/api/tab.php?tab=pulse">Pulse</a>
      <a class="btn" href="/api/tab.php?tab=motion">Motion</a>
    </nav>
    <div id="bo-panel" class="bo-panel" aria-live="polite"><p class="muted" style="margin:0">Plain links — boosted into AJAX. Without JavaScript they would simply navigate.</p></div>

    More examples

    Server response with OOB elements

    HTML
    <!-- swapped into the request's target -->
    <li>Mug — $12</li>
    <!-- swapped by id, anywhere on the page -->
    <span id="cart-count" kj-swap-oob="true">4</span>
    <div kj-swap-oob="beforeend:#toasts"><p>Added to cart</p></div>

    API

    kj-swap="innerHTML | outerHTML | beforebegin | afterbegin | beforeend | afterend | delete | none | textContent [swap:Ns settle:Ns scroll:top show:… focus-scroll:true transition:true ignoreTitle:true]"

    How it goes in, with htmx's modifiers (View Transitions for transition:true).

    Reference: kj-swap →
    kj-select="css" · kj-select-oob="#a, #b:innerHTML" · kj-swap-oob="true | swap:css" · kj-preserve

    Pick part of the response; swap extra pieces elsewhere; keep live elements.

    Reference: kj-select →
    $.hyper.ajax(verb, url, target | { target, swap, values, headers, select }) · $.hyper.swap · $.hyper.config · $.hyper.defineSwap · $.process(el)

    Programmatic access.

    Reference: $.hyper →

    Migrating

    Coming from htmxhx-boost, hx-swap-oob and hx-select-oob behave the same as kj-boost, kj-swap-oob and kj-select-oob; responses written for htmx (with hx-swap-oob) also work.

    Related features