npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

resonantjs

v1.2.0

Published

A lightweight JavaScript framework that enables reactive data-binding for building dynamic and responsive web applications. It simplifies creating interactive UIs by automatically updating the DOM when your data changes.

Readme

ResonantJs

npm version License: MIT

Reactive data-binding for vanilla JavaScript. No build step. No virtual DOM. Just HTML attributes and plain objects.

<span res="count"></span>
<button onclick="count++">+1</button>

<script src="https://unpkg.com/resonantjs@latest/resonant.min.js"></script>
<script>
  const res = new Resonant();
  res.add('count', 0);
</script>

Change count anywhere in your code and the DOM updates automatically.


Install

npm install resonantjs

Or drop in a script tag:

<script src="https://unpkg.com/resonantjs@latest/resonant.min.js"></script>

~18 KB minified. Zero dependencies.


Why ResonantJs?

| | | |---|---| | No build tools | Works with a single <script> tag. Ship today. | | Familiar mental model | Plain objects, plain arrays, plain HTML. No JSX, no templates, no compilation. | | Automatic DOM updates | Change a value, the page updates. Arrays, nested objects, computed properties -- all reactive. | | Selective re-rendering | Only the changed array item re-renders. Siblings stay untouched. | | Built-in persistence | One flag to sync any variable to localStorage. | | Tiny footprint | ~18 KB minified, zero dependencies. |


Quick Tour

Bind a variable

<h1>Hello, <span res="name"></span></h1>
const res = new Resonant();
res.add('name', 'World');

name = 'ResonantJs'; // DOM updates instantly

Bind an object

<div res="user">
  <span res-prop="name"></span>
  <span res-prop="email"></span>
</div>
res.add('user', { name: 'Alice', email: '[email protected]' });

user.name = 'Bob'; // only the name span updates

Render an array

Place res on a template element inside a list container. ResonantJs clones it once per item.

<ul>
  <li res="tasks">
    <span res-prop="title"></span>
    <button res-onclick-remove="id">x</button>
  </li>
</ul>
res.add('tasks', [
  { id: 1, title: 'Learn ResonantJs' },
  { id: 2, title: 'Ship a feature' }
]);

tasks.push({ id: 3, title: 'Profit' }); // new <li> appears
tasks[0].title = 'Done!';                // only that <li> re-renders

Conditional display

<div res-display="user.isAdmin">Admin Panel</div>
<div res-display="tasks.length === 0">No tasks yet.</div>

Dynamic classes

<span res-prop="title" res-style="done ? 'completed' : ''"></span>

Computed properties

Derived values that recalculate automatically when dependencies change. Chains work too.

res.add('price', 100);
res.add('taxRate', 0.08);

res.computed('tax',   () => price * taxRate);
res.computed('total', () => price + tax);    // chains: updates when tax updates
Total: $<span res="total"></span>

Two-way input binding

<input type="text" res="name" />
<input type="checkbox" res="settings.darkMode" />
<select res="country">...</select>

Persistence

res.add('theme', 'light', true); // third arg = persist to localStorage
theme = 'dark';                  // saved automatically

Bind existing variables

Already have a variable on window? Register it without passing a value.

window.username = 'Alice';
res.add('username');       // picks up 'Alice', makes it reactive
res.add('username', true); // same, but also persists to localStorage

Event handling

<button res-onclick="editTask">Edit</button>      <!-- receives the current item -->
<button res-onclick-remove="id">Delete</button>    <!-- removes item by matching property -->

Callbacks

res.addCallback('tasks', (value, item, action) => {
  console.log(action, item); // 'added', 'removed', 'modified', etc.
});

Build a Todo App

Copy this into an .html file and open it in your browser.

<!doctype html>
<html>
<head>
  <style>.done { text-decoration: line-through; color: #999; }</style>
  <script src="https://unpkg.com/resonantjs@latest/resonant.min.js"></script>
</head>
<body>
  <h1>Todos (<span res="tasks.length"></span>)</h1>

  <input placeholder="Add a task..." res="newTask" />
  <button onclick="addTask()">Add</button>

  <ul>
    <li res="tasks">
      <input type="checkbox" res-prop="done" />
      <span res-prop="name" res-style="done ? 'done' : ''"></span>
      <button res-onclick="removeTask">x</button>
    </li>
  </ul>

  <script>
    const res = new Resonant();
    res.addAll({
      newTask: '',
      tasks: [
        { name: 'Learn ResonantJs', done: false },
        { name: 'Ship a feature', done: true }
      ]
    });

    function addTask() {
      const title = newTask.trim();
      if (!title) return;
      tasks.unshift({ name: title, done: false });
      newTask = '';
    }

    function removeTask(item) {
      const idx = tasks.indexOf(item);
      if (idx !== -1) tasks.delete(idx);
    }
  </script>
</body>
</html>

API Reference

JavaScript

| Method | Description | |---|---| | new Resonant() | Create an instance | | .add(name, value?, persist?) | Add a reactive variable. Omit value to bind an existing window variable. Pass true as second or third arg to persist to localStorage. | | .addAll({ name: value, ... }) | Add multiple variables at once | | .addCallback(name, fn) | Listen for changes. fn(currentValue, item, action) | | .computed(name, fn) | Define a read-only derived value |

HTML Attributes

| Attribute | Description | |---|---| | res="varName" | Bind element to a variable (scalar, object, or array template) | | res-prop="key" | Bind to an object property within a res context | | res-display="expr" | Show/hide element based on a JS expression | | res-style="expr" | Apply CSS classes from a JS expression | | res-onclick="fnName" | Call a global function on click; receives current item if in an array | | res-onclick-remove="prop" | Remove the current item from its parent array by matching property |

Array Methods

Reactive arrays support all standard methods plus:

| Method | Description | |---|---| | .set(index, value) | Update item at index | | .delete(index) | Remove item at index | | .update(newArray) | Replace entire array contents | | .filterInPlace(fn) | Mutating filter | | .forceUpdate() | Force re-render without changing data |

Callback Actions

added removed modified updated filtered


Performance

  • Selective array re-rendering -- when a property on one array item changes, only that item's DOM subtree is updated. Siblings are untouched, including their res-display and res-style evaluations.
  • Batched updates -- rapid changes within the same tick are coalesced into a single DOM update.
  • Computed property chains -- cascading computed properties resolve in dependency order within a single pass.
  • Stable keys -- array items are tracked by stable keys for efficient reuse during re-renders.

Browser Support

Chrome 60+ / Firefox 55+ / Safari 12+ / Edge 79+ / Mobile browsers


Examples


Development

git clone https://github.com/amurgola/ResonantJs.git
cd ResonantJs
npm install
npm test          # run all tests
npm run build     # run tests + minify

License

MIT -- see LICENSE.


GitHub · npm · Issues

Built by Andrew Paul Murgola