AuthonAuthon Blog
debugging6 min read

How to do partial page updates without shipping a framework

Native partial DOM updates are surprisingly hard. Here's why libraries like HTMX exist, what Chrome is reportedly exploring, and how to handle it cleanly today.

AW
Alan West
Authon Team
How to do partial page updates without shipping a framework

The problem: swapping part of a page is harder than it should be

You click a "Load more" button. Behind the scenes, your app fetches some HTML and shoves it into a

. Simple, right?

Except it never stays simple. You hit edge cases with orphaned event listeners, focus jumping around, scripts that mysteriously don't execute, and weird flashes when you replace a chunk of DOM.

I ran into this again last month while refactoring a dashboard. The team had jQuery doing partial swaps for the better part of a decade and finally wanted out. The "modern" alternatives all looked great in demos. Each one came with its own quirks.

Why the web makes this awkward

HTML, at its core, doesn't have a primitive for "replace this region with the contents of that response." You can navigate the whole page (,

), or you can call fetch() and write the result into innerHTML yourself. There's no middle ground built into the platform.

That gap is why entire categories of tools exist:

  • HTMX turns attributes into AJAX swaps
  • Turbo (Hotwire) wraps regions in and intercepts navigation
  • React/Vue/Svelte rebuild the page from a virtual representation
  • Unpoly and friends do progressive enhancement around forms

Each of them is solving a problem the browser itself never tried to solve.

A quick tour of the pain

Here's the typical "just fetch and replace" approach:

js
// Replace #content with HTML from the server
async function loadFragment(url) {
  const res = await fetch(url);
  const html = await res.text();
  document.querySelector('#content').innerHTML = html;
}

Looks fine. But:

  • Inline How to do partial page updates without shipping a framework | Authon Blog