DEV Community

Cover image for JavaScript and the Dream of Controlling Reactivity
Huỳnh Nhân Quốc
Huỳnh Nhân Quốc

Posted on

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>``
Enter fullscreen mode Exit fullscreen mode

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

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

Top comments (0)