Show HN: Mador – Make any DOM reactive with a tiny 80-line Proxy state tuple

bosmarcel 84 points 24 comments September 06, 2026
github.com · View on Hacker News

Discussion Highlights (11 comments)

bosmarcel

Hey HN! I wanted to see how far you can push modern JavaScript Proxies without all the heavy overhead of a traditional framework. The result is Mador: a tiny ~80-line reactive state tuple ([r, w]) that lets you make any DOM element reactive using a simple CSS selector, automated dependency tracking, and batched microtasks. No build steps required—just drop it in. I built this over the weekend just to experiment with clean, zero-dependency reactivity. Would love to hear your thoughts or see where you'd run into limits with something like this!

DylanMerigaud

Clean launch, good luck!

ahmedhossamdev

Great work!

moostee

Proposed variant optimised for human readaiblity... ```js import mador from "mador"; const [read, write] = mador({ count: 1 }); read(".counter", ctx => ctx.el.textContent = ctx.count); write(".increment", "click", ctx => ctx.count++); write(ctx => ctx.count = 0); ``` ## Read Dependencies are detected automatically when the read function is run during initiation. ```js read(".counter", ctx => ctx.el.textContent = `Count: ${ctx.count}`); ``` ## Write Immediate: ```js write(ctx => ctx.count++); ``` Event-triggered: ```js write(".increment", "click", ctx => ctx.count++); ``` Event writes expose `ctx.el` and `ctx.event`.

PoignardAzur

Are reactive updates based on deep equality or reference equality?

dpweb

The core idiom I've used for years is deliberately tiny: fully encapsulated custom Web Components that simply re-render when matching an attribute and `window.state` changes. Data model is simply: window.state = new Proxy({}, { set(target, key, value) { target[key] = value document.querySelectorAll(`[data="${key}"]`) .forEach(el => el.render?.()) return true } }) handles reactivity.. https://github.com/digplan/vanilla-light

bedroom_jabroni

There are many standalone plug-n-play implementations of the signal primitive in JS. To name a few: preact/signals, vue reactivity, etc, there's even a TC39 proposal for a lang feature. Is this meant to stand out by doing things differently or reinvent them?

hamburglar

> Hey HN! I wanted to see how far you can push modern JavaScript Proxies without all the heavy overhead of a traditional framework. The result is Mador: a tiny ~80-line reactive state tuple ([r, w]) that lets you make any DOM element reactive using a simple CSS selector, automated dependency tracking, and batched microtasks. No build steps required—just drop it in. I built this over the weekend just to experiment with clean, zero-dependency reactivity. Would love to hear your thoughts or see where you'd run into limits with something like this! Unsure why this comment from the author was flagged/dead but it certainly doesn’t seem to run afoul of HN guidelines.

afavour

I’m curious to know what performance looks like. In the recesses of my memory is the belief that proxies are not good for performance but I have no idea if that’s well founded (or maybe once was but isn’t any more). It’s a very smart idea though, I like it.

abosalehworld

I love the minimalist approach here. Using Proxies for state management without the heavy overhead of large frameworks is really elegant. Keeping it under 80 lines is impressive. Great work!

codedokode

The syntax looks a bit too verbose for me. And function names like "read" and "write" are confusing too, given that "read" function isn't made for reading values. Cannot we use a single function for binding, like this (and name it "bind")? let counter = proxy({ count: 0 }); bind('.counter', (el) => el.textContent = counter.count); counter.count++; // Queues DOM update Also, > Mador is distributed as an ES module. This means it cannot be used on a page opened from disk, and the user needs to set up a HTTP server which is time-consuming and distracting. And you cannot distribute an app as as HTML file.

Semantic search powered by Rivestack pgvector
5,720 stories · 51,803 chunks indexed