hnq.me
all articles
2025-11-03 Substack 1

JavaScript and the Dream of Controlling Reactivity

A journey to control reactive UIs — light, safe, and flexible — from raw DOM manipulation, through countless frameworks, to building my own reactive engine using JavaScript Proxy.

Article context 2025-11-03
Substack 1 reactions
JavaScript and the Dream of Controlling Reactivity

🌱 The Journey Begins

About five years ago, I shared a deeply personal approach to building web components — one rooted in Web Components and custom elements.

My idea was simple:
Define a new element, give it its own behavior, and interact directly with it — without re-rendering the entire DOM.

If you’ve ever opened YouTube → View Source, you’ll see how they structure their custom elements and attach isolated logic to each.
That’s what inspired me when I started.

So I built a tiny “engine” that allowed interaction with each element independently — minimizing DOM reflows, maximizing control.
The goal was clear: maximum control, minimal interference.

🤔 When Doubt Creeps In

At first, it all seemed to work perfectly.
But as projects grew, I faced an inevitable truth:

Direct DOM manipulation — while powerful — isn’t always scalable or optimal.

When I needed to extend or reuse components, I found myself repeating a lot of manual steps.
That made me question:

“Is there a way to keep my control philosophy, but also benefit from what modern JS frameworks offer?”

🔁 Rewriting with a New Philosophy

I started experimenting again — combining my own understanding with the strengths of existing frameworks.

When I learned about Virtual DOM, I saw how it solved certain problems — but it wasn’t what I truly needed.
I wanted something simpler.

And then a new philosophy emerged:

Write less. Do more.

My old process was:

  1. Mark the DOM.

  2. Use JS to find and bind elements.

  3. Write interactive logic directly on them.

It gave me 100% behavioral control — but at a high cost in time and maintainability.

🧩 The Solutions I Studied

I explored several libraries with similar philosophies:

  • Alpine.js – lightweight, easy to integrate, HTML-like syntax.

  • Web Components – standards-based, framework-free, but verbose.

  • HTMX – minimal JavaScript, great for server-driven UI.

  • AngularJS 1.x – early reactive pioneer, but too heavy for small features.

  • Petite-vue – a compact version of Vue, lovely but still limited.

Each had its strengths, yet I still longed for something smaller, tighter, more controllable.

⚡ Discovering Proxy and My First Reactive Engine

A turning point came last year, while developing a data table component for a client.
To optimize data updates, I discovered JavaScript Proxy — a surprisingly elegant tool for creating reactive data without relying on a complex virtual DOM.

Proxy felt smooth.
But then, the same old pain returned: every new feature meant rewriting parts of the engine from scratch.
The dev loop became: build → fix → rewrite → repeat.

So I decided to go deeper — to build my first true reactive engine, designed around how I naturally structure components.

🚫 Why I Didn’t Choose Mainstream Frameworks

I didn’t go with React, Angular, or Vue (full) because:

  • They were too heavy for my needs.

  • Not optimized for SSR (Server-Side Rendering) in my workflow.

  • They often required rewriting backend logic — I use Golang, and I didn’t want that friction.

jQuery still survives today because it solves practical problems quickly.
But I needed something even lighter, modern, and controllable.

🧠 The Development Philosophy: Micro Component

I imagine Micro Components like Microservices:

  • Each component does exactly one thing.

  • It can run independently.

  • It can hydrate anywhere, anytime.

This lets me embed mini JavaScript apps into mobile or web environments — without affecting other modules.
Since SEO is already handled by the server, I can focus purely on enhancing user experience on the client.

⚙️ Example: How It Works

<div
  data-kitmodule-component=”counter”
  data-counter-state=”count: 0”
>
  <input data-counter-model=”count” />
  <button data-counter-event=”click:count++”>+</button>
  <span data-counter-bind=”count”></span>
</div>

Explanation:

  • data-kitmodule-component — identifies the component.

  • data-counter-state — declares the initial state.

  • data-counter-model — two-way data binding with input.

  • data-counter-event — attaches event handlers directly via attributes.

  • data-counter-bind — updates the DOM when the state changes.

The result:
A lightweight, framework-free, yet fully reactive component.

🌸 What I Learned

This journey taught me that simplicity is often the ultimate sophistication.
Reactive doesn’t have to mean Virtual DOM or complex syntax.

Sometimes, all you need is:

  • a small engine,

  • readable, HTML-based syntax,

  • and a sprinkle of smart JavaScript.

In the next part, I’ll share the detailed architecture of this reactive engine —
how it parses expressions, binds events, and syncs state with the DOM without using eval or Function constructors — ensuring CSP safety and XSS protection.

open: https://github.com/kitmodule/kitjs

📝 NOTES

  • Originally written in 2025, reposted with updates.

  • AI-powered translation from Vietnamese.

  • Read the original Vietnamese version here: [LINK_TO_ORIGINAL]

☕ More about me

Thanks for reading Huỳnh Nhân Quốc Substack! Subscribe for free to receive new posts and support my work.

Share this article

Search