Hyper · htmx-style

History & deep links

kj-push-url updates the address bar after a successful swap, so tabs and filters become shareable links. A tiny popstate handler makes Back work.

Set kj-push-url="true" to push the request URL, or give it a specific path or query such as ?tab=motion. jsKjs calls history.pushState after the swap succeeds.

Restoring state on Back/Forward is deliberately left to you — it is a few lines, and you know best what "state" means for your page. The demo below also reads the URL on load, so this link opens the Motion tab directly.

Live · Tabs with shareable URLs

Choose a tab — then look at the address bar, and try your Back button.
View the source for this demo
HTML
<div class="row" id="pu-tabs" aria-label="Modules">
  <button type="button" data-tab="core" aria-pressed="false" kj-get="/api/tab.php?tab=core" kj-target="#pu-panel" kj-push-url="?tab=core">Core</button>
  <button type="button" data-tab="hyper" aria-pressed="false" kj-get="/api/tab.php?tab=hyper" kj-target="#pu-panel" kj-push-url="?tab=hyper">Hyper</button>
  <button type="button" data-tab="pulse" aria-pressed="false" kj-get="/api/tab.php?tab=pulse" kj-target="#pu-panel" kj-push-url="?tab=pulse">Pulse</button>
  <button type="button" data-tab="motion" aria-pressed="false" kj-get="/api/tab.php?tab=motion" kj-target="#pu-panel" kj-push-url="?tab=motion">Motion</button>
</div>
<div id="pu-panel" class="plate" aria-live="polite" style="box-shadow:none;margin-top:12px">Choose a tab — then look at the address bar, and try your Back button.</div>
JavaScript
const mark = tab => $('#pu-tabs button').each(function () {
  $(this).attr('aria-pressed', String(this.dataset.tab === tab));
});
const tabFromUrl = () => new URLSearchParams(location.search).get('tab');

$('#pu-tabs').on('click', 'button', function () { mark(this.dataset.tab); });

// Back / Forward: reload whatever the URL says
$(window).on('popstate', () => {
  const tab = tabFromUrl() || 'core';
  mark(tab);
  $('#pu-panel').load('/api/tab.php?tab=' + encodeURIComponent(tab));
});

// Deep link: ?tab=motion opens Motion straight away
if (tabFromUrl()) $(window).trigger('popstate');

More examples

Push the request URL itself

HTML
<a href="/products?page=2" kj-get="/products?page=2" kj-target="#grid" kj-push-url="true">Page 2</a>

API

kj-push-url="true | /path"

Push the request URL (or a given path) into browser history after a successful swap.

Reference: kj-push-url →

Migrating

Coming from htmxLike hx-push-url, minus htmx's history cache and automatic restore. hx-replace-url and hx-boost are not included.

Related features