<include-iframe> Web Component
In The Simplest Ways to Handle HTML Includes (2021) Chris Coyier described HTML includes as "taking a piece of HTML and putting it right inside another piece of HTML". He makes up the following example to illustrate the idea:
<body
<include src="./header.html"></include> Content
Body
<include src="./footer.html"></include> footer
</body
Although this looks so native, it doesn't work in the browser. This has motivated a bunch of people to mimic this behavior in various ways – lets jump into a little recap.
A brief history of client-side HTML includes
2014/11/07
Joshua Peek commits version 1.0.0 of a web component that currently has about 27k downloads per month on NPM:
<include-fragment src="/include.html">.
<p>Loading tip...</p>
</include-fragment>.
On page load, the
include-fragment
element fetches the URL, the response is parsed into an HTML element, which replaces the include-fragment element entirely.
2019/04/14
In HTML Includes That Work Today Scott Jehl describes a neat way to use iframes for includes with a tiny script:
<iframe
src="/include.html"
onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"
></iframe>
[...] the code uses an
iframe
to load the file, and anonload
event to inject theiframe
’s content just before the iframe in the HTML, before deleting theiframe
itself.
Shortly thereafter, Andy Bell demonstrates Scott's concept being wrapped in a web component:
<import-content
path="/include.html"
loading="lazy"
></import-content>
2019/07/16
Just two days after Scott's post, Justin Fagnani releases another web component that uses fetch()
under the hood:
<html-include
src="/include.html"
></html-include>
By default
<html-include>
renders the HTML in a shadow root, so it's isolated from the rest of the page.
2024/07/11
5 years later HTML includes are still not available. One day, two people in my Mastodon newsfeed independently (?) post about this topic:
Not a day goes by when I work on my website that I don't wish for a simpler setup. No SSG. No npm. No tooling. Just simple HTML with partials imports, vanilla CSS, and whatever vanilla JS is necessary for enhancements.
I just want the HTML partials imports. Why don't we have them already?!
– Sara Soueidan
you can build a simple, maintainable website that serves zero JS by using nonstandard tooling (like Preact/Astro) on the server.
you cannot do the same by following web standards. that just makes me sad.
– Mayank
2024/09/01
Keith Cirkel (who is now the maintainer of <include-fragment>
) releases another web component, which has more features than I can count, but it's base looks like this:
<i-html
src="/include.html"
>Loading...</i-html>
[
i-html
] remains in the DOM, and can re-fetch contents again and again.
2024/09/08
One week later, Max Böck discusses how "Going Buildless" can work nowadays and presents a simple Web Component, which uses fetch()
and replaces itself:
<html-include
src="./include.html"
></html-include>
He even shows an example how to pre-render this component on the server/edge side.
<include-iframe>
: Another Web Component
So here we are, 6 concepts and 5 web components later. Let me happily introduce another one: include-iframe
(Demo, GitHub, NPM):
<include-iframe>
<iframe src="./include.html"></iframe>
<div slot="loading" hidden>Loading...</div>
</include-iframe>
It injects the content of a slotted
<iframe>
element and replaces itself and theiframe
afterwards.
Thanks to this architecture, it supports all the benefits already described by Scott Jehl, especially in terms of performance and Progressive Enhancement.
Besides the web component itself, I only implemented two additional features:
A loading
slot that e. g. can show skeletons or loading spinners, which effectively enables the concept of Astro's Server Islands. You should now see pulsating skeletons, as the included HTML takes 20 seconds before it's ready.
I also implemented query-head
and query-body
attributes, which allow you to select which elements or even styles should be injected, having in mind the concept of Single File Components.
In the following, the CSS of this entire component has been injected into the document.
Reflection
A thing I would love to see in future instead of a custom element would be the usage of custom attributes, which are not available as well (Proposal on GitHub, but could lead to the following markup:
<iframe src="./include.html" include-iframe-body></iframe>
Besides that I'm looking forward to have this component in my toolbelt. I already enjoy it so much, that I introduced the concept of Server Islands utilizing include-iframe
into my Statamic CMS to defer server-heavy content. Let's see what follows next.