| Event | Fires on | When | detail |
|---|---|---|---|
kj:before | requesting element | before the request | { url, verb } |
kj:after | requesting element | response received, before the swap | { url, verb, html } |
kj:error | requesting element | network error or non-2xx status | { url, verb, error } (error.status) |
kj:load | target (or its parent, if outerHTML replaced it) | after the swap | { url, verb } |
Responses land here.
View the source for this demo
HTML
<div class="lc-bar" aria-hidden="true"><div id="lc-progress"></div></div>
<div class="row">
<button type="button" kj-get="/api/quote.html" kj-target="#lc-target">Succeeds</button>
<button type="button" kj-get="/api/slow.php?ms=1400" kj-target="#lc-target">Slow (1.4 s)</button>
<button type="button" kj-get="/api/fail.php?code=500" kj-target="#lc-target">Fails (500)</button>
</div>
<div id="lc-target" class="plate" aria-live="polite" style="box-shadow:none;margin-top:12px;min-height:3.2em">Responses land here.</div>
<pre class="out" id="lc-log"></pre>JavaScript
const t0 = performance.now();
const log = (name, text) => $('#lc-log').text(
('+' + Math.round(performance.now() - t0) + 'ms ' + name.padEnd(10) + text + '\n' + $('#lc-log').text()).split('\n').slice(0, 9).join('\n'));
let inflight = 0;
$(document).on('kj:before', (e, d) => {
inflight++;
$('#lc-progress').css({ opacity: 1, width: '70%' });
log('kj:before', d.verb.toUpperCase() + ' ' + d.url);
});
$(document).on('kj:after', (e, d) => log('kj:after', d.url + ' (' + d.html.length + ' bytes)'));
$(document).on('kj:error', (e, d) => {
log('kj:error', d.url + ' → HTTP ' + d.error.status);
$('#lc-target').text('Something went wrong (HTTP ' + d.error.status + '). Try again.');
});
$(document).on('kj:load', e => log('kj:load', '#' + e.target.id + ' updated'));
$(document).on('kj:after kj:error', () => {
if (--inflight > 0) return;
$('#lc-progress').css('width', '100%');
setTimeout(() => $('#lc-progress').css({ opacity: 0, width: '0%' }), 450);
});More examples
Global error toast
JavaScript
$(document).on('kj:error', (e, { url, error }) => {
showToast(error.status === 401 ? 'Please sign in again' : 'Request to ' + url + ' failed');
});API
kj:before · kj:after · kj:error · kj:load
kj:before (before the request), kj:after (response received, before the swap; detail.html) and kj:error (detail.error.status) fire on the requesting element. kj:load fires on the target after the swap — or on its former parent when outerHTML replaced it. All bubble.
Migrating
Coming from htmxRough equivalents:
htmx:beforeRequest → kj:before, htmx:afterRequest → kj:after, htmx:responseError → kj:error, htmx:afterSwap → kj:load. Events are not cancelable.Related features
Core
Custom events
Decouple your UI with custom events: trigger("cart:add", payload) once and let any number of independent listeners react.
Open →HyperConfirmations & loading indicators
Ask before destructive requests with kj-confirm and show progress with kj-indicator.
Open →HyperPolling
Keep a panel fresh with kj-trigger="every Ns".
Open →