Parker Davis

htmz - a low power tool for html

I came across htmz this week and after a few chuckles reading through the landing page I was excited to try it out. Its a really fun and clever way to swap HTML fragments without full page reloads using a super minimal script (~166 bytes).

This is essentially all there is to it:

<iframe
hidden
name="htmz"
onload="setTimeout(()=>document.querySelector(contentWindow.location.hash||null)?.replaceWith(...contentDocument.body.childNodes))"
></iframe>

The htmz website gives a good and engaging overview so I direct your attention there first. The purpose of this post is to go through what each piece of the snippet does and explain to myself, in more detail than necessary, exactly how it works.

What does this snippet do?

I haven't done much with iframes since working on my high school band's website in the early 2000s so I had to remind myself a bit about how they work. I'm surprised they aren't used more in modern web development honestly - they're fun.

You can set targets for anchor links. The target you see most often is target="_blank" which opens a link in a new window. If you have iframes on the page, you can target them by referencing their name. To use htmz you set the target for links to a hidden iframe named htmz.

Optionally, if you include a base element anywhere in your HTML document with a target of “htmz”, this automatically adds the target to all links on the page.

<base target="htmz" />

With the target set, clicking a link loads the content in the hidden iframe, which when it finishes loading, triggers a script.

The onload script

Let’s take a look at the expanded “hacker” version where the script and iframe are separated out:

<script>
function htmz(frame) {
setTimeout(() =>
document
.querySelector(frame.contentWindow.location.hash || null)
?.replaceWith(...frame.contentDocument.body.children)
);
}
</script>
<iframe hidden name="htmz" onload="htmz(this)"></iframe>

First up, there’s an optional setTimeout to add the function call to the end of the queue in the event loop.

Then, it searches the document with a querySelector.

The query selector starts with frame, the parameter of the function. When you pass in this as the argument on the iframe onload function call, it refers to itself, the iframe html element. (This self-referential pointing around is omitted in the condensed all-in-one snippet.)

.contentWindow – returns the window object of the embedded iframe

.location – returns the URL of the window

.hash – returns the hash (#) and the string that follows (if present – otherwise it returns an empty string). In the URL context, hashes are usually used to navigate to an ID on the page. In this case it is being used as a CSS selector within the querySelector to grab the element on the page where you want the new content to be inserted.

The || null is there to prevent an uncaught DOM exception from the querySelector, in case the location loaded in the hidden iframe does not include a hash.

Similarly, the question mark allows optional chaining where if the expression on the left side of the question mark evaluates to null or undefined it will short-circuit the overall expression and return undefined instead of throwing an error.

.replaceWith() – replaces the selected HTML element with the nodes passed in as arguments.

...frame.contentDocument.body.children uses rest parameter syntax to allow the replaceWith() function to accept an indefinite number of arguments as an array – which in this case is all of the children elements of the body loaded within the hidden iframe.

From MDN: “Spread syntax looks exactly like rest syntax. In a way, spread syntax is the opposite of rest syntax. Spread syntax “expands” an array into its elements, while rest syntax collects multiple elements and “condenses” them into a single element. See rest parameters and rest property.”

So, the content is loaded in the hidden iframe then copied wherever you specify. As the htmz documentation puts it:

htmz is essentially a proxy target.

Like how a proxy server forwards requests to some specified server, proxy target htmz forwards responses into some specified target.”

Go check out the examples on htmz. There are some complex UIs that can be created with very little client-side javascript. I probably wouldn’t reach for this if my needs were too complex but it’s a cool technique for loading simple interactive content within a page.

See what I mean?

55

Comments

Leave a comment