What's in the add-on
kj-collapse— animates height to and fromautoalongsidekj-show.$persist(value)— keeps akj-dataproperty inlocalStorage(or.using(sessionStorage)) across reloads.kj-trap— keeps keyboard focus inside an element while the expression is true, and restores it afterwards.kj-mask— formats input as it is typed (9digit,aletter,*anything);kj-mask:dynamicwith$money($input)for currency.kj-intersectandkj-resize— run an expression when the element enters the viewport or changes size.
kj-collapse
A jQuery-compatible library with htmx, Alpine and GSAP features built in. This panel's height animates to auto.
$persist
You've loaded this page time(s). Reload — the count survives.
kj-mask
kj-trap
Tab cycles inside here. Escape or Close to leave.
View the source for this demo
<div class="grid g2" style="gap:14px" kj-data="{ open: false, visits: $persist(0).as('kj-demo-visits'), phone: '', price: '', trap: false }" kj-init="visits++">
<div class="ui-box"><h4>kj-collapse</h4>
<button type="button" @click="open = !open" :aria-expanded="open">What is jsKjs?</button>
<div kj-show="open" kj-collapse><p style="margin:10px 0 0">A jQuery-compatible library with htmx, Alpine and GSAP features built in. This panel's height animates to <code>auto</code>.</p></div>
</div>
<div class="ui-box"><h4>$persist</h4>
<p style="margin:0">You've loaded this page <b kj-text="visits"></b> time(s). Reload — the count survives.</p>
<button type="button" style="margin-top:8px" @click="visits = 0">Reset</button>
</div>
<div class="ui-box"><h4>kj-mask</h4>
<div class="field"><label for="ui-phone">Phone</label><input id="ui-phone" kj-mask="(999) 999-9999" kj-model="phone" inputmode="numeric" placeholder="(555) 123-4567"></div>
<div class="field"><label for="ui-price">Price</label><input id="ui-price" kj-mask:dynamic="$money($input)" kj-model="price" inputmode="decimal" placeholder="1,234.00"></div>
</div>
<div class="ui-box"><h4>kj-trap</h4>
<button type="button" @click="trap = true">Open trapped panel</button>
<div kj-show="trap" kj-trap="trap" @keydown.escape="trap = false" style="margin-top:10px" role="group" aria-label="Trapped panel">
<p style="margin:0 0 6px">Tab cycles inside here. Escape or Close to leave.</p>
<input aria-label="First field" placeholder="First"> <input aria-label="Second field" placeholder="Second">
<button type="button" @click="trap = false">Close</button>
</div>
</div>
</div>More examples
Lazy work with kj-intersect, layout with kj-resize
<img kj-intersect.once="$el.src = $el.dataset.src" data-src="/big.jpg" alt="…">
<div kj-data="{ w: 0 }" kj-resize="w = $width"><span kj-text="w > 600 ? 'wide' : 'narrow'"></span></div>API
Alpine's official plugins, as Pulse directives.
Reference: jskjs.ui.js →Available inside every expression.
Reference: Magics →Migrating
x-collapse → kj-collapse, $persist unchanged, x-trap → kj-trap.Related features
Transitions
Fade, scale and slide elements in and out when kj-show or kj-if changes, using kj-transition modifiers or your own CSS classes.
Open →PulseReactive state
Declare state on an element with kj-data and every binding inside updates when it changes.
Open →PulseTwo-way binding
Bind form controls to state in both directions with kj-model — text, number, range, checkbox, radio and select.
Open →