A jQuery plugin that adds reactive state and declarative DOM binding. Without a build step, a virtual DOM, or a component model.
Most jQuery projects hit the same wall: a piece of UI depends on more than a couple of values, and keeping the DOM manually in sync starts getting messy fast. You end up with code like this:
// Vanilla jQuery. Imperative, brittle
$('#inc').on('click', function() {
count++;
$('.counter-display').text(count);
$('.step-tracker').text(`Step ${count} of 10`);
if (count >= 10) $('.done-msg').show();
updateProgressBar(count);
});
Every time count changes you have to remember every element that depends on it. Add a
new display element and you're back editing every event handler. Miss one and you have a
stale-display bug.
reQuery inverts that relationship. State is the source of truth. HTML declares what depends on it:
<!-- HTML: declare what depends on state -->
<span data-rq-text="count"></span>
<span data-rq-text="count" id="step-tracker"></span>
<div data-rq-show="isDone">All done!</div>
$('#app').rqState({ count: 0, isDone: false });
$('#inc').on('click', () =>
$('#app').rqMutate('count', n => {
const next = n + 1;
$('#app').rqSet('isDone', next >= 10);
return next;
})
);
Adding a new element that displays count? One HTML attribute. No event handler edits.
The handlers only change state. They no longer care about the DOM.
reQuery is not for greenfield SPA development. For that, use Vue, React, or Svelte.
State lives in a WeakMap keyed to the root element. Not a global store. Two
widgets on the same page have fully independent state.
When state changes, reQuery walks the subtree, finds data-rq-* bindings for
the changed key, and updates those nodes directly. No diffing, no reconciler.
All methods on $.fn, selector-first, read methods return values, write
methods return this for chaining.
Add these attributes to any element inside your root and reQuery keeps them in sync automatically.
| Attribute | Effect |
|---|---|
data-rq-text="key" |
Sets textContent |
data-rq-html="key" |
Sets innerHTML |
data-rq-val="key" |
Sets input value; also wires input/change for two-way
binding |
data-rq-show="key" |
Toggles visibility via display based on truthiness |
data-rq-attr-[name]="key" |
Sets an HTML attribute; passes null to remove it |
data-rq-class-[name]="key" |
Adds or removes a CSS class based on truthiness |
data-rq-each="key" |
Clones a <template> child for each item in an array |
data-rq-on-[event]="action" |
Wires an event to a named handler from opts.actions |
All methods are registered on $.fn and follow
standard jQuery chaining patterns.
| Method | Returns | Description |
|---|---|---|
rqState(obj, opts?) |
this |
Initialize state on an element; runs initial binding pass |
rqGet(key) |
value | Read a state value |
rqSet(key, value) |
this |
Write a state value; triggers watchers and DOM update |
rqMutate(key, fn) |
this |
Update state via callback. Receives current value, returns next |
rqWatch(key, fn) |
this |
Register a callback that fires after state is written |
rqComputed(key, fn) |
this |
Register a derived value; re-runs whenever dependencies change |
rqReset(key?) |
this |
Reset to initial values; pass a key to reset one property, or omit to reset all |
rqDestroy() |
this |
Remove state, unbind listeners, and clean up the element |
Extend the API with
$.reQuery.use(fn) — see the Plugin System section below.
$.reQuery.use(pluginFn) is a controlled extension
point. The function receives a context object that exposes core internals, letting you add new
$.fn.rq* methods without touching core source.
$.reQuery.use(function(ctx) {
ctx.$.fn.rqLog = function() {
return this.each(function() {
var rec = ctx.getRecord(this);
if (rec) console.log('[reQuery]', rec.data);
});
};
});
The context object exposes:
$, getRecord(el), setState(el, key, value)
mutateState(el, key, fn), addWatcher(el, key, fn),
addComputed(el, key, fn)
The reference plugin is
src/plugins/rq-validate.js. A form validation plugin and worked example for anyone
building their own.
reQuery fills a specific gap. It's not trying to be React.
| reQuery | Vanilla jQuery | Vue / React / Svelte | |
|---|---|---|---|
| Requires a build step | No | No | Yes |
| Requires rewriting existing code | No | — | Yes |
| Reactive data binding | Yes | No | Yes |
| Virtual DOM / diffing | No | No | Yes (React, Vue) |
| Works inside CMS-rendered HTML | Yes | Yes | Difficult |
| Full SPA capability | No | No | Yes |
| Bundle size (approx.) | ~5 KB | ~30 KB | 30–100+ KB |
Drop it in via script tag. No bundler required.
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script src="dist/requery.umd.js"></script>
import $ from 'jquery';
import 'requery';
<div id="app">
<p>Count: <strong data-rq-text="count"></strong></p>
<button id="inc">+</button>
</div>
<script>
$('#app').rqState({ count: 0 });
$('#inc').on('click', () => $('#app').rqMutate('count', n => n + 1));
</script>
No compilation. No configuration. No framework to learn.
An advanced reQuery demo. Reactive bindings, state, and DOM manipulation with no build step.