DEV Community

Cover image for Building Reactive MPAs in 2KB: Meet Flynt.js
Marcel Bos
Marcel Bos

Posted on

Building Reactive MPAs in 2KB: Meet Flynt.js

Why I Built Flynt.js: Reactivity Without Messy HTML Clutter

If you build Multi-Page Applications (MPAs) using Laravel Blade, Twig, or classic SSR, you've probably used Alpine.js. It's awesome for quick reactivity, but as your components grow, your HTML quickly turns into this:

<!-- The Alpine.js HTML clutter we all know... -->
<div x-data="{ open: false, items: [], fetch() { ... } }" x-init="fetch()">
  <button @click="open = !open" :disabled="loading">Toggle</button>
</div>
Enter fullscreen mode Exit fullscreen mode

I loved the lightweight nature of Alpine, but I hated losing Separation of Concerns. Why are we jamming entire JS functions inside HTML attributes?

I wanted something different: The reactivity of modern frameworks, but with clean HTML and strict Presenter-based architecture.

So I built Flynt.js.

What is Flynt.js?

Flynt.js (~2KB) brings the Presenter Pattern to MPAs. Your HTML stays 100% clean, referencing only behavior via data-fx attributes:

<div data-fx="productPresenter">
  <select data-fx="productPresenter.sortBtn">...</select>
  <ul data-fx="productPresenter.productListing"></ul>
  <button data-fx="productPresenter.loadMoreBtn">Load more</button>
</div>
Enter fullscreen mode Exit fullscreen mode

All logic lives in clean, testable JavaScript presenters with direct DOM reactivity:

<script>
window.productPresenter = fx.presenter(({ createState, render, map }) => {
  const state = createState({ loading: false, products: [] });

  return {
    loadMoreBtn(el) {
      el.onclick = () => fetchMoreProducts();
      render(() => {
        el.disabled = state.loading;
      });
    },
    productListing(el) {
      const mapProducts = map(el);
      render(() => {
        const items = state.products.map(prod => ({
          key: prod.id,
          html: `<li class="card">${prod.title}</li>`
        }));
        mapProducts(items); // Efficient key-based DOM updates!
      }));
    }
  };
});
</script>
Enter fullscreen mode Exit fullscreen mode

The Secret Weapon: map(el)

Unlike other micro-libraries that force you to re-render entire innerHTML blocks or mess with virtual DOMs, Flynt includes a native map() helper. It updates real DOM items in-place based on unique keys.

Key Features

๐Ÿงน Zero HTML clutter: Keep templates pristine.

โšก Ultra-lightweight: ~2KB runtime, zero dependencies.

๐Ÿ”„ Direct DOM Reactivity: createState + render loops without Virtual DOM overhead.

๐Ÿ“ฆ No build step required: Works directly via <script> tag

Check out the GitHub repo, star it if you like the approach, and let me know your thoughts!

๐Ÿ‘‰ GitHub: https://github.com/marsbos/flynt.js

Top comments (0)