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.
View the source for this demo
<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>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
<a href="/products?page=2" kj-get="/products?page=2" kj-target="#grid" kj-push-url="true">Page 2</a>API
Push the request URL (or a given path) into browser history after a successful swap.
Reference: kj-push-url →Migrating
hx-push-url, minus htmx's history cache and automatic restore. hx-replace-url and hx-boost are not included.Related features
Declarative requests
Make GET, POST, PUT, PATCH and DELETE requests straight from HTML with kj-get, kj-post and friends — htmx-style hypermedia with zero JavaScript.
Open →CoreLoading HTML fragments
Fetch a page and insert only the fragment you need with $(el).load("/page.html #section") — the classic jQuery partial-loading pattern on fetch..
Open →HyperRequest lifecycle events
Every declarative request emits bubbling lifecycle events — kj:before, kj:after, kj:error and kj:load — so one document-level listener can drive a page-wide progress bar or error toast..
Open →