Create a store with an initial object; read it anywhere with $.store('cart'), in expressions or in JavaScript. Getters work as computed values. Mutating the store re-renders every component on the page.
Persistence is a few lines: load the initial value from localStorage, and save on pagehide. The cart below survives a refresh.
Mini cart
View the source for this demo
<div class="row" style="justify-content:space-between">
<strong>Rack Shop</strong>
<span kj-data="{}" class="chip" aria-live="polite" kj-text="'🛒 ' + $.store('cart').count + ' items · $' + $.store('cart').total"></span>
</div>
<div kj-data="shop" class="gs-grid">
<button type="button" @click="add('Patch cable', 9)">Patch cable · $9</button>
<button type="button" @click="add('Easing mug', 18)">Easing mug · $18</button>
<button type="button" @click="add('Tween tee', 24)">Tween tee · $24</button>
</div>
<div kj-data="minicart" class="plate" style="box-shadow:none;margin-top:14px">
<h4 style="margin:0 0 6px">Mini cart</h4>
<ul class="list-plain" kj-html="list()"></ul>
<button type="button" @click="$.store('cart').items = []" :disabled="!$.store('cart').count" style="margin-top:10px">Empty cart</button>
</div>let saved = [];
try { saved = JSON.parse(localStorage.getItem('kj-demo-cart')) || []; } catch (e) {}
$.store('cart', {
items: saved,
get count() { return this.items.length; },
get total() { return this.items.reduce((sum, i) => sum + i.price, 0); },
});
$.component('shop', () => ({
add(name, price) { $.store('cart').items.push({ name, price }); },
}));
$.component('minicart', () => ({
remove(i) { $.store('cart').items.splice(i, 1); },
list() {
const items = $.store('cart').items;
if (!items.length) return '<li class="muted">Your cart is empty.</li>';
return items.map((it, i) => '<li class="gs-line">' + $.escape(it.name) + ' <span>$' + it.price +
' <button type="button" @click="remove(' + i + ')" aria-label="Remove ' + $.escape(it.name) + '">✕</button></span></li>').join('');
},
}));
$(window).on('pagehide', () => {
try { localStorage.setItem('kj-demo-cart', JSON.stringify($.store('cart').items)); } catch (e) {}
});More examples
Use a store from plain JavaScript
const prefs = $.store('prefs', { theme: 'dark', compact: false });
$('#compact').on('change', function () { prefs.compact = this.checked; }); // every component updatesAPI
Create or retrieve a global reactive store. Any component reading it re-renders when it changes. Getters work as computed values.
Reference: $.store() →A standalone reactive proxy without auto-rendering — for your own change-tracking logic.
Reference: $.reactive() →Migrating
Alpine.store('cart', …) → $.store('cart', …); read it as $.store('cart') instead of $store.cart.Related features
Reusable components
Register a component once with $.component(name, factory) and reuse it anywhere with kj-data="name(args)".
Open →CoreCustom events
Decouple your UI with custom events: trigger("cart:add", payload) once and let any number of independent listeners react.
Open →PulseReactive state
Declare state on an element with kj-data and every binding inside updates when it changes.
Open →