Are we solving the information-centric transclusion problem,
or the design-centric asset reuse problem?
An iframe is fine for the former but is not geared towards design and layout solutions.
It kinda sucks for both! Dropping in a box of text that flatly does not resize to fit its contents does not fit the definition of "fine" for me, here.
You can do some really silly maneuvers with `window.postMessage` to communicate an expected size between the parent and frame on resize, but that's expensive and fiddly.
If you want to include HTML sandboxes, we have iframes. If you want it served from the server, it's just text. Putting text A inside text B is a solved problem.
> Putting text A inside text B is a solved problem.
Yes, but in regards to HTML it hasn't been solved in a standard way, it's been solved in hundreds, if not thousands of non standard ways. The point of the article is that having one standard way wlcould reduce a lot of complexity from the ecosystem, as ES6 imports did.
The simplest answer is that HTML wasn't designed as a presentation language, but a hypertext document language. CSS and Javascripts were add-ons after the fact. Images weren't even in the first version. Once usage of the web grew beyond the initial vision, solutions like server-side includes and server-side languages that rendered HTML were sufficient.
I think the best examples of HTML in that regard is HTML-rendered info pages[0], for Emacs and its ecosystem. Then you have the same content presented in HTML [1]. Templates were enough in the first case. Includes are better in the second case due to common assets external to the content.
Headers and their menus are often problematic for this approach, unless they are 100% static (e.g. HN would work but Reddit and Google wouldn't since they both put things in their header which can expand over the content). I.e. you can make it transparent but that doesn't solve eating the interactions. The code needed to work around that is more than just using JS to do the imports.
<iframe> is different from what the author is asking for, it has its own DOM and etc. He wants something like an SSI but client side. He explains some of the problems right after the part you cut off above
"We’ve got <iframe>, which technically is a pure HTML solution, but they are bad for overall performance, accessibility, and generally extremely awkward here"
The article asks about includes but also about imports ("HTML cannot import HTML ") which this is very directly.
This feature was billed as #includes for the web [1]. No, it acts nothing like an #include. TBH I don't see why ES modules are a "replacement" here.
Personally I would like to see something like these imports come back, as a way to reuse HTML structure across pages, BUT purely declaratively (no JS needed).
#includes where partially formed HTML (ie, header.html has a <body> open tag and footer.html has the closing tag) isn't very DOM compatible.
After researching this very topic earlier; SSI is the most pragmatic solution. Check out Caddy's Template Language (based on Go), it is quite capable and quite similar to building themes in Hugo. Just much more bare bones.
I have built several sites with pure HTML+CSS, sprinkled with some light SSI with Caddy, and it is rock solid and very performant!
Originally, iframe were the solution, like the posts mentions. By the time iframes became unfashionable, nobody was writing HTML with their bare hands anymore. Since then, people use a myriad of other tools and, as also mentioned, they all have a way to fix this.
So the only group who would benefit from a better iframe is the group of people who don't use any tools and write their HTML with their bare hands in 2025. That is an astonishing small group. Even if you use a script to convert markdown files to blog posts, you already fall outside of it.
No-one needs it, so the iframe does not get reinvented.
what if it could be a larger group though? modern css has been advancing rather rapidly... I don't even need a preprocessing library any more... I've got nested rules, variables, even some light data handling... why not start beefing up html too? we've got some new features but includes would be killer
No, originally frameset[0] and frame[1] were the solution to this problem. I remember building a website in the late 1990s with frameset. iframe came later, and basically allowed you to do frames without the frameset. Anyway, frameset is also the reason every browser's user agent starts with "Mozilla".
This was the rabbit hole that I started down in the late 90s and still haven’t come out of. I was the webmaster of the Analog Science Fiction website and I was building tons of static pages, each with the same header and side bar. It drove me nuts. So I did some research and found out about Apache server side includes. Woo hoo! Keeping it DRY (before I knew DRY was a thing).
Yeah, we’ve been solving this over and over in different ways. For those saying that iframes are good enough, they’re not. Iframes don’t expand to fit content. And server side solutions require a server. Why not have a simple client side method for this? I think it’s a valid question. Now that we’re fixing a lot of the irritation in web development, it seems worth considering.
You can message the page dimensions to the parent. To do it x domain you can load the same url into the parent with the height in the #location hash. It won't refresh that way.
I know it’s possible to work around it, but that’s not the point. This is such a common use case that it seems worthwhile to pave the cowpath. We’ve paved a lot of cowpaths that are far less trodden than this one. This is practically a cow superhighway.
We’ve built an industry around solving this problem. What if, for some basic web publishing use cases, we could replace a complex web framework with one new tag?
> XHTML 2 takes a completely different approach, by taking the premise that all images have a long description and treating the image and the text as equivalents. In XHTML 2 any element may have a @src attribute, which specifies a resource (such as an image) to load instead of the element.
The content of the div can be used to support legacy browsers. It can have a link, iframe, a message or an outdated version of the content/menu/header/footer etc
> We’ve built an industry around solving this problem. What if, for some basic web publishing use cases, we could replace a complex web framework with one new tag?
I actually did that replacement, with a few enhancements (maybe 100 lines of code, total?). It's in arxiv pending at the moment. In about two days it will be done and I'll post a Show HN here.
I mean in 1996s netscape you could do this (I run the server for a website that still uses this):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html>
<frameset cols="1000, *">
<frame src="FRAMESET_navigation.html" name="navigation">
<frame src="FRAMESET_home.html" name="in">
</frameset>
</html>
The thing that always bugged me about frames is that they are too clever. I don't want to reload only the frame html when I rightclick and reload. Sure the idea was to cache those separately, but come on — frames and caching are meant to solve two different problems and by munching them together they somewhat sucked at solving either.
To me includes for HTML should work in the dumbest way possible. And that means: Take the text from the include and paste it where the include was and give the browser the resulting text.
If you want to cache a nav section separately because it appears the same on every page lets add a cache attribute that solves the problem independently:
HTML is a markup language, not a programming language. It's like asking why Markdown can't handle includes. Some Markdown editors support them (just like some server-side tools do for HTML), but not all.
No, HTML is fundamentally different because (for a static site without any JS dom manipulation) it has all the semantic content, while stylesheets, images, objects, etc. are just about presentation.
I think the distinction is "semantic on what level/perspective?". An image packaged as a binary blob is semantically opaque until it is rendered. Meanwhile, seeing <img> in the HTML or the file extension .jpg in any context that displays file extensions tells me some information right out of the gate. And note that all three of these examples are different information: the HTML tag tells me it's an image, whereas the file extension tells me it's a JPEG image, and the image tells me what the image contains. HTML is an example of some kind of separation, as it can tell you some semantic meaning of the data without telling you all of it. Distinguishing and then actually separating semantics means data can be interpreted with different semantics, and we usually choose to focus on one alternative interpretation. Then I can say that HTML alone regards some semantics (e.g. there is an image here) while disregarding others (e.g. the image is an image of a brick house).
I'm not sure what isn't computing. Presumably you know (or have looked up) the meaning of "semantic"? Images and videos are graphic, not semantic, content. To the extent they are rendering semantic content, that content should be described in the alt tag.
This isn’t programming. It’s transclusion[0]. Essentially, iframes and images are already forms of transclusion, so why not transclude html and have the iframe expand to fit the content?
As I wrote that, I realized there could be cumulative layout shift, so that’s an argument against. To avoid that, the browser would have to download all transcluded content before rendering. In the past, this would have been a dealbreaker, but maybe it’s more feasible now with http multiplexing.
With Early Hints (HTTP code 103), it seems especially feasible. You can start downloading the included content one round-trip after the first byte is sent.
Including another document is much closer to a markup operation than a programming operation. We already include styles, scripts, images, videos, fonts...why not document fragments?
Markdown can't do most of those, so it makes more sense why it doesn't have includes, but I'd still argue it definitely should. I generally dislike LaTeX, but about the only thing I liked about it when writing my thesis was that I could have each chapter in its own file and just include all of them in the main file.
I'm not defending it, because when I started web development this was one of the first problems I ran into as well -- how the heck do you include a common header.
But the original concept of HTML was standalone documents, not websites with reusable components like headers and footers and navbars.
That being said, I still don't understand why then the frames monstrosity was invented, rather than a basic include. To save on bandwidth or something?
Frames were widely abused by early web apps to do dynamic interfaces before XHR was invented/widely supported. The "app" had a bunch of sub-frames with all the links and forms carefully pointing to different frames in the frameset.
A link in a sidebar frame would open a link in the "editor" frame which loaded a page with a normal HTML form. Submitting the form reloaded it in that same frame. Often the form would have multiple submit buttons, one to save edits in progress and another to submit the completed form and move to the next step. The current app state was maintained server side and validation was often handled there save for some basic formatting client side JavaScript could handle.
This setup allowed even the most primitive frame-supporting browsers to use CRUD web apps. IIRC early web frameworks like WebObjects leaned into that model of web app.
Oh my goodness, yes you're right, I'd forgotten entirely about those.
They were horrible -- you'd hit the back button and only one of the frames would go back and then the app would be in an inconsistent state... it was a mess!
You needed to hit the reset button (and hoped it worked) and never the back button! Yes, I suffered through early SAP web apps built entirely with frames and HTML forms. It was terrible.
I don't love JavaScript monstrosities but XHR and dynamic HTML were a vast improvement over HTML forms and frame/iframe abuse.
Really well written web form applications were a delight in 2001 and a large improvement over conventional applications written in Windows. It helped that application data was in a SQL database, with a schema, protected by transactions, etc as opposed to a tangle of pointers that would eventually go bad and crash the app -- I made very complicated forms for demographic profiling, scientific paper submission, application submission, document search, etc. If you did not use "session" variables for application state this could at worst cause a desynchronization between the browser and the server which (1) would get resynchronized at any load or reload and (2) never get the system into a "stuck" state from the user viewpoint and (3) never lose more than a screen full of work.
Try some other architecture though and all bets were off.
Amazon's web store looked and worked mostly the same as it does now, people were very impressed with MapQuest, etc.
Applications like that can feel really fast, almost desktop application fast, if you are running them on a powerful desktop computer and viewing them on another computer or tablet over a LAN
The original concept of HTML was as an SGML subset, and SGML had this functionality, precisely because it's very handy for document authoring to be able to share common snippets.
I think of all the “hygienic macro” sorts of problems. You really ought to be able to transclude a chunk of HTML and the associated CSS into another document but you have to watch out for ‘id’ being unique never mind the same names being used for CSS classes. Figuring out the rendering intent for CSS could also be complicated: the guest CSS might be written like
.container .style { … }
Where the container is basically the whole guest document but you still want those rules to apply…. Maybe, you want the guest text to appear in the same font as the host document but you still want colors and font weights to apply. Maybe you want to make the colors muted to be consistent with the host document, maybe the background of the host document is different and the guest text isn’t contrasts enough anymore, etc.
> The optimal solution would be using a template engine to generate static documents.
This helps the creator, but not the consumer, right? That is, if I visit 100 of your static documents created with a template engine, then I'll still be downloading some identical content 100 times.
XSLT solved this problem. But it had poor tool support (DreamWeaver etc) and a bunch of anti-XML sentiment I assume as blowback from capital-E Enterprise stacks going insane with XML for everything.
XSLT did exactly what HTML includes could do and more. The user agent could cache stylesheets or if it wanted override a linked stylesheet (like with CSS) and transform the raw data any way it wanted.
I'll still be downloading some identical content 100 times.
That doesn't seem like a significant problem at all, on the consumer side.
What is this identical content across 100 different pages? Page header, footer, sidebar? The text content of those should be small relative to the unique page content, so who cares?
Usually most of the weight is images, scripts and CSS, and those don't need to be duplicated.
If the common text content is large for some reason, put the small dynamic part in an iframe, or swap it out with javascript.
If anyone has a genuine example of a site where redundant HTML content across multiple pages caused significant bloat, I'd be interested to hear about it.
I care! It is unnecessary complexity, and frankly ugly. If you can avoid repetition, then you should, even if the reason is not obvious.
To give you a concrete example, consider caching (or, equivalently, compiling) web pages. Maybe you have 100 articles, which share a common header and footer. If you make a change to the header, then all 100 articles have to be uncached/rebuilt. Why? Because somebody did not remove the duplication when they had the chance :-)
I used the seamless attribute extensively in the past, it still doesn't work the way GP intended, which is to fit in the layout flow, for example to take the full width provided by the parent, or automatically resize the height (the pain of years of my career)
It worked rather like a reverse shadow DOM, allowing CSS from the parent document to leak into the child, removing borders and other visual chrome that would make it distinguishable from the host, except you still had to use fixed CSS layouts and resize it with JS.
That’s the reason it doesn’t get implemented. Nobody wants the simple I/O operation based inclusion. The moment you try to propose it, there’ll be demands to add conditional logic or macros. More relevant for the web is instantiating html templates, which will undoubtedly get piled onto such a feature. And pretty soon you have yet another:
The difference between "a line of JS" and a standardized declarative solution is of course that a meek "line of $turing_complete_language" can not, in the general case, be known and trusted to do what it purports to do, and nothing else; you've basically enabled any kind of computation, and any kind of behavior. With an include tag or attribute that's different; it's behavior is described by standards, and (except for knowing what content we might be pulling in) we can 100% tell the effects from static analysis, that is, without executing the code. With "a line of JS" the only way, in the general case, to know what it does is to run it (an infinite number of times). Also, because it's not standardized, it's much harder to save to disk, to index and to archive it.
this here is the main idea of HTMX - extended to work for any tag p, div, content, aside …
there are many examples of HTMX (since it is a self contained and tiny) being used alongside existing frameworks
of course for some of us, since HTMX brings dynamic UX to back end frameworks, it is a way of life https://harcstack.org (warning - raku code may hurt your eyes)
If you want it more straight-forward and simple hypermedia approach, then check out https://data-star.dev (highly recommended, there are great youtube video's where the maintainers discuss their insights). Following up where htmx took things.
Server-side includes FTW! When a buddy and I started making "web stuff" back in the mid-90s the idea of DRY also just made sense to us.
My dialup ISP back then didn't disable using .htaccess files in the web space they provided to end users. That meant I could turn on server-side includes! Later I figured out how to enable CGI. (I even went so far as to code rudimentary webshells in Perl just so I could explore the webserver box...)
> Woo hoo! Keeping it DRY (before I knew DRY was a thing)
I still remember the script I wrote to replace thousands (literally) slightly different headers and footers in some large websites of the 90s. How liberating to finally have that.
As a dev from the early 90s, I share the sentiment. Watching javascript become more and more complex and bloated for little to no benefit to the end user.
I think this is a genuinely good question that I was also wondering some time ago.
And it is a genuinely good question!
I think the answer of PD says feels the truest.
JS/CSS with all its bureaucracy are nothing compared to HTML it seems. Maybe people don't find nothing wrong with Html, maybe if they do, they just reach out for js/css and try to fix html (ahem frontend frameworks).
That being said, I have just regurgitated what PD says has said and I give him full credit of that but I am also genuinely confused as to why I have heard that JS / CSS are bureaucratic (I remember that there was this fireship video of types being added in JS and I think I had watched it atleast 1 year ago (can be wrong) but I haven't heard anything for it and I see a lot of JS proposals just stuck from my observation
And yet HTML is such level of bureaucratic that the answer to why HTML doesn't have a feature is because of its bureaucracy. Maybe someone can explain the history of it and why?
Initially HTML was less about the presentation layer and more about the "document" concept. Documents should be self-contained, outside of references to other documents.
I still think this is the best web. Either you are a collection of interlinked documents and forms (manual pages, wiki,...), or you are a full application (figma, gmail, google docs). But a lot of sites are trying to be both. And somes are trying to be one while they are the other type.
One document == one HTML page was never the idea. Documents are often way too long to comfortably read and navigate that way. Breaking them into sections and linking between them was part of the core idea of HTML.
Includes are a standard part of many document systems. Headers and footers are a perfect example - if I update a document I certainly don't want to update the document revision number on every single page! It also allows you to add navigation between documents in a way that is easy to maintain.
LaTeX can do it. Microsoft Word can do it (in a typically horrible Microsoftian way). Why not HTML?
I guess for the similar reason that Markdown does not have any "include" ability -- it is a feature not useful enough yet with too many issues to deal with. They are really intended to be used as "single" documents.
> We’ve got <iframe>, which technically is a pure HTML solution, but they are bad for overall performance, accessibility, and generally extremely awkward here
What does this mean? This is a pure HTML solution, not just "technically" but in reality. (And before iframe there were frames and frameset). Just because the author doesn't like them don't make them non-existent.
An iframe is a window into another webpage, and is bounded as such both visually and in terms of DOM interfaces. A simple example would be that an iframe header can't have drop-down menus that overlap content from the page hosting it.
They are categorically not the same DX/UX as SSI et al. and it's absolutely bizarre to me that there's so many comments making this complaint.
The real problem with iframes is that their size is set by the parent document only.
They would be a lot more useful if we could write e.g. <iframe src=abc.html height=auto width=100> so the height of the iframe element is set by the abc.html document instead of the parent document.
"Includes" functionality is considered to be server-side, i.e. handled outside of the web browser. HTML is client-side, and really just a markup syntax, not a programming language.
As the article says, the problem is a solved one. The "includes" issue is how every web design student learns about PHP. In most CMSes, "includes" become "template partials" and are one of the first things explained in the documentation.
There really isn't any need to make includes available through just HTML. HTML is a presentation format and doesn't do anything interesting without CSS and JS anyway.
Agree with what you said, however, HTML is a document description language and not a presentation format. CSS is for presentation (assuming you meant styling).
HTML is a markup language that identifies the functional role of bits of text. In that sense, it is there to provide information about how to present the text, and is thus a presentation format.
It is also a document description language, because almost all document description languages are also a presentation format.
That's why I joked about flamebait, it's hypertext though, aren't anchors essentially a goToURL() click handler in some ways? Template partials seem like a basic part of this system.
> considered to be server-side
Good point! Wouldn't fetching a template partial happen the same way (like fetching an image?)
It stands for "markup language", and was inherited from SGML, which had includes. Strictly speaking, so did early HTML (since it was just an SGML subset), it's just that browsers didn't bother implementing it, for the most part. So it's not that it didn't evolve, but rather it devolved.
Nor is this something unique to SGML. XML is also a "markup language", yet XInclude is a thing.
> "Includes" functionality is considered to be server-side, i.e. handled outside of the web browser. HTML is client-side, and really just a markup syntax, not a programming language.
That's not an argument that client-side includes shouldn't happen. In fact HTML already has worse versions of this via frames and iframes. A client-side equivalent of a server-side include fits naturally into what people do with HTML.
I think it feels off because an HTML file can include scripts, fonts, images, videos, styles, and probably a few other things. But not HTML. It can probably be coded with a custom element (<include src=.../>). I would be surprised if there wasn't a github repo with something similar.
> "Includes" functionality is considered to be server-side
Exactly! Include makes perfect sense on server-side.
But client-side include means that the client should be able to modify original DOM at unknown moment of time. Options are
1. at HTML parse time (before even DOM is generated). This requires synchronous request to server for the inclusion. Not desirable.
2. after DOM creation: <include src=""> (or whatever) needs to appear in the DOM, chunk loaded asynchronously and then the <include> DOM element(sic!) needs to be replaced(or how?) by external fragment. This disables any existing DOM structure validation mechanism.
Having said that...
I've implemented <include> in my Sciter engine using strategy #1. It works there as HTML in Sciter usually comes from local app resources / file system where price of issuing additional "get chunk" request is negligible.
> As the article says, the problem is a solved one.
It's "solved" only in the sense that you need to use a programming language on the server to "solve" it. If all you are doing is static pages, it's most definitely not solved.
Then you just pre-build the page before publishing it. It's way cheaper as you do the work once, instead of every client being much slower because they have to do additional requests.
By "whole 'build' process", do you think something like a makefile or do you think something more advanced is required?
One drawback though would be that one indeed would have to maintain dependencies, which would be error prone beyond simply adding headers and footers... I wonder if one could (ab)use CPP [1] and its -M option to do that.
Well, that very much depends on your definition of slow, doesn't it?
An additional request is another round trip. That can be very slow. Average TTFB on the internet in the US is ~0.7 seconds.
It's much faster to send it as part of the same request as you then don't have to wait for the browser to discover it, request it, wait for the response and then add it.
A build process does not have to be complicated, at all. If you can write HTML then using something that can simply read the HTML includes you wish existed and swap it with the specified filename is trivial.
Ofc, the idea has many other issues, like how to handle dependencies of the included HTML, how to handle conflicts, what oath to use and many more.
> Then you just pre-build the page before publishing it.
That's "using a programming language to solve the problem", isn't it?
> It's way cheaper as you do the work once, instead of every client being much slower because they have to do additional requests.
What work do client-side includes have to do other than fetching the page (which will get cached anyway)? It's less work to have a `<include-remote ...>` builtin than even a simple Makefile on the server.
It does not have to be a programming language on the server, no, unless you want to. The server can have a static site, that you build as you deploy it.
Fetching another resource is expensive. It's another round trip, and depending on many factors it could be another second to load the page. And if the HTML includes other nested HTML then it can be much slower.
This is the exact thing we try to avoid when building websites that perform well. You want as few chained requests as possible, and you want the browser to be aware of them as soon as possible, with the correct priority. That way the browser can get the important stuff needed to display content fast.
Including HTML client side for templating is just wasteful, slow and dumb from a technical standpoint.
Every client would have to do another request for each include. It would literally be many thousands of times slower(or worse) than doing it locally where the templates can be in memory as you render the pre-render the pages. You also save a ton of CPU cycles and bandwidth, by not serving more files with additional overhead like headers.
> It would literally be many thousands of times slower(or worse) than doing it locally where the templates can be in memory as you render the pre-render the pages.
Yeah, it's not. I'm doing client side includes and the includes get cached by the browser. I'm sure I would have noticed if my pages went from 1s to display to 1000s to display.
If you have a site/webapp with (say) twenty pages, that's only two extra requests for both header and footer.
Isn't this what proper framesets (not iframes) were supposed to do a long time ago (HTML 4?). At least they autoexpanded just fine and the user could even adjust the size to their preference.
There was a lot of criticism for frames [1] but still they were successfully deployed for useful stuff like Java API documentation [2].
In my opinion the whole thing didn't stay mostly because of too little flexibility for designer: Framesets were probably well enough for useful information pages but didn't account for all the designers' needs with their bulky scrollbars and limited number of subspaces on the screen. Today it is too late to revive them because framesets as-is wouldn't probably work well on mobile...
Issue with frame set was way more fundamental: No deep linking, thus people coming via bookmarks or Google (or predecessor) were left on a page without navigation, which people then tried working around with JavaScript, which never gave it a good experience.
Nowdays it is sometimes the other way around: Pages are all JavaScript so no good experience in the first place. I have encountered difficulty trying to get a proper “link” to something multiple times. Also, given that Browsers love to reduce/hide the address bar I wonder if it is really still that important a feature.
Of course "back then" this was an important feature and one of the reasons for getting rid of frames :)
So, HTML did have includes and they fell out of favor.
The actual term include is an XML feature and it’s that feature the article is hoping for. HTML had an alternate approach that came into existence before XML. That approach was frames. Frames did much more than XML includes and so HTML never gained that feature. Frames lost favor due to misuse, security, accessibility, and variety of other concerns.
Unlike Framesets I think XML includes were never really supported in many browsers (or even any major browsers)?
I still like to use them occasionally but it incurs a "compilation" step to evaluate them prior to handing the result of this compilation to the users/browsers.
As it happens, the major browsers still can do XML 'includes' to some extent, since by some miracle they haven't torn out their support for XSLT 1.0. E.g. this outputs "FizzBuzz" on Firefox:
Yep, and this can be used to e.g. make a basically static site template and then do an include for `userdata.xml` to decorate your page with the logged in user's info (e.g. on HN, adding your username in the top right, highlighting your comments and showing the edit/delete buttons, etc.). You can for example include into a variable `<xsl:variable name="myinfo" select="document('userdata.xml')"/>` and then use it in xpath expressions like `$myinfo/user/@id`. Extremely simple, good for caching, lightweight, very high performance. Easy to fail gracefully to the logged out template. You basically get your data "API" for free since you're returning XML in your data model. I will never understand why it didn't take off.
XML includes are blocking because XSL support hasn't been updated for 25 years, but there's no reason why we couldn't have it async by now if resources were devoted to this instead of webusb etc.
You'd better not jinx it: XSL support seems like just the sort of thing browser devs would want to tear out in the name of reducing attack surface. They already dislike the better-known SVG and never add any new features to it. I often worry that the status quo persists only because they haven't really thought about it in the last 20 years.
I’ve used XSLT in anger - I used it to build Excel worksheets (in XML format) using libXSLT. I found it very verbose and hard to read. And Xpath is pretty torturous.
I wish I could have used Javascript. I wish Office objects were halfway as easy to compose as the DOM. I know a lot of people hate on Javascript and the DOM, but it’s way easier to work with than the alternatives.
I would guess back in the days having extra requests was expensive, thus discouraged. Later there were attempts via xinclude, but by then PHP and similar took over or people tolerated frames.
I'm not an expert on this but IMO, from a language point of view, HTML is a markup language, it 'must' have no logic or processing. It is there to structure the information not to dynamically change it. Nor even to display it nicely.
The logic is performed elsewhere. If you were to have includes directly in HTML, it means that browsers must implement logic for HTML. So it is not 'just' a parser anymore.
Imagine for example that I create an infinite loop of includes, who is responsible to limit me? How to ensure that all other browsers implement it in the same way?
What happens if I perform an injection from another website? Then we start to have cors policy management to write. (iframes were bad for this)
Now imagine using Javascript I inject an include somewhere, should the website reload in some way? So we have a dynamic DOM in HTML?
I understand your point, but I still think it is bad from the point of view of language paradigms[1]. Iframes should have not been created in the first place.. You are changing the purpose of the language while it was not made for it.
(yes in my view I interpret includes as a basic procedure)
There is a very, very broad line in that "no logic or processing". HTML/CSS already do a lot of logic and processing. And many "markup languages" have include support. Like wikitext used in wikipedia and includes in Asciidoc.
* the actual existence of frames (although those are deprecated)
* iframes (which are not deprecated, so seemingly doing declarative inclusion of HTML in HTML was not what was wrong with frames)
* imports in CSS, which share some of the same problems / concerns as HTML imports
* the existence of JavaScript with its ability to change anything on the page, including the ability to issue HTTP requests and be written arbitrarily obfuscated ways.
Ward Cunningham (inventor of the Wiki) spent some time trying to invent a transclusion-first wiki, where everyone had their own wiki-space and used transclusion socially https://en.wikipedia.org/wiki/Federated_Wiki
I think true transclusion would be more than that.
In Xanadu you could transclude just an excerpt from one document into another document.
If you wanted to do this with HTML you need an answer for the CSS. In any particular case you can solve it, making judgements about which attributes should be consistent between the host document, the guest document and the guest-embedded-in-host. The general case, however, is unclear.
For a straightforward <include ...> tag the guest document is engineered to live inside the CSS environment (descendant of the 3rd div child of a p that has class ".rodney") that the host puts it in.
Another straightforward answer is the Shadow DOM which, for the most part, lets the guest style itself without affecting the rest of the document. I think in that case the host can still put some styles in to patch the guest.
We discussed this back when creating web components, but the focus quickly became about SPA applications instead of MPAs and the demand for features like this was low in that space.
I wish I would have advocated more for it though. I think it would be pretty easy to add using a new attribute on <script> since the parser already pauses there, so making something like <script transclude={url}> would likely not be too difficult.
honestly, html can include css and javascript via link and style tags. there's no reason for it to not have an <include src="" /> tag, and let the browser parsing it fetch the content to replace it.
366 comments
[ 3.1 ms ] story [ 302 ms ] threadThis post does link to a technique (new to me) to extract iframe contents:
[0]: https://www.filamentgroup.com/lab/html-includes/
You can do some really silly maneuvers with `window.postMessage` to communicate an expected size between the parent and frame on resize, but that's expensive and fiddly.
The host can then act as a server for the iframe client, even updating it's state or DOM in response to a message from the iframe.
Yes, but in regards to HTML it hasn't been solved in a standard way, it's been solved in hundreds, if not thousands of non standard ways. The point of the article is that having one standard way wlcould reduce a lot of complexity from the ecosystem, as ES6 imports did.
[0]: https://www.gnu.org/software/emacs/manual/html_node/emacs/in...
[1]: https://emacsdocs.org/docs/emacs/The-Emacs-Editor
> We’ve got <iframe>, which technically is a pure HTML solution, but
And then on the following paragraph..
> But none of the solutions is HTML
> None of these are a straightforward HTML tag
Not sure what the point is. Maybe just complaining
"We’ve got <iframe>, which technically is a pure HTML solution, but they are bad for overall performance, accessibility, and generally extremely awkward here"
https://caniuse.com/imports
- JS for functionality via the custom elements API - HTML for layout via <template> tags. - CSS for aesthetics via <style> tags.
Not for just quickly and simply inserting the contents of header.html at a specific location in the DOM.
This feature was billed as #includes for the web [1]. No, it acts nothing like an #include. TBH I don't see why ES modules are a "replacement" here.
Personally I would like to see something like these imports come back, as a way to reuse HTML structure across pages, BUT purely declaratively (no JS needed).
#includes where partially formed HTML (ie, header.html has a <body> open tag and footer.html has the closing tag) isn't very DOM compatible.
[1] https://web.archive.org/web/20181121181125/https://www.html5...
https://en.wikipedia.org/wiki/Server_Side_Includes
I have built several sites with pure HTML+CSS, sprinkled with some light SSI with Caddy, and it is rock solid and very performant!
Originally, iframe were the solution, like the posts mentions. By the time iframes became unfashionable, nobody was writing HTML with their bare hands anymore. Since then, people use a myriad of other tools and, as also mentioned, they all have a way to fix this.
So the only group who would benefit from a better iframe is the group of people who don't use any tools and write their HTML with their bare hands in 2025. That is an astonishing small group. Even if you use a script to convert markdown files to blog posts, you already fall outside of it.
No-one needs it, so the iframe does not get reinvented.
[0] https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/...
[1] https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/...
Yeah, we’ve been solving this over and over in different ways. For those saying that iframes are good enough, they’re not. Iframes don’t expand to fit content. And server side solutions require a server. Why not have a simple client side method for this? I think it’s a valid question. Now that we’re fixing a lot of the irritation in web development, it seems worth considering.
We’ve built an industry around solving this problem. What if, for some basic web publishing use cases, we could replace a complex web framework with one new tag?
<div src="foo.txt"></div>
> XHTML 2 takes a completely different approach, by taking the premise that all images have a long description and treating the image and the text as equivalents. In XHTML 2 any element may have a @src attribute, which specifies a resource (such as an image) to load instead of the element.
I actually did that replacement, with a few enhancements (maybe 100 lines of code, total?). It's in arxiv pending at the moment. In about two days it will be done and I'll post a Show HN here.
To me includes for HTML should work in the dumbest way possible. And that means: Take the text from the include and paste it where the include was and give the browser the resulting text.
If you want to cache a nav section separately because it appears the same on every page lets add a cache attribute that solves the problem independently:
To tell the browser it should load the inner html or the src of that element from cache if it has it.Now you could convince me thst the include should allow for more, but it being dumb is a feature not a bug.
It’s made to pull in external resources (as opposed to other document formats like PDF).
Scripts, stylesheets, images, objects, favicons, etc. HTML is thematically similar.
The only one that is presentational is stylesheets.
https://developer.mozilla.org/en-US/docs/Web/CSS/content
Something in that tenet does not compute with me.
As I wrote that, I realized there could be cumulative layout shift, so that’s an argument against. To avoid that, the browser would have to download all transcluded content before rendering. In the past, this would have been a dealbreaker, but maybe it’s more feasible now with http multiplexing.
[0] https://en.m.wikipedia.org/wiki/Transclusion#Client-side_HTM...
Markdown can't do most of those, so it makes more sense why it doesn't have includes, but I'd still argue it definitely should. I generally dislike LaTeX, but about the only thing I liked about it when writing my thesis was that I could have each chapter in its own file and just include all of them in the main file.
I'm not defending it, because when I started web development this was one of the first problems I ran into as well -- how the heck do you include a common header.
But the original concept of HTML was standalone documents, not websites with reusable components like headers and footers and navbars.
That being said, I still don't understand why then the frames monstrosity was invented, rather than a basic include. To save on bandwidth or something?
Lots of gateways between systems.
A link in a sidebar frame would open a link in the "editor" frame which loaded a page with a normal HTML form. Submitting the form reloaded it in that same frame. Often the form would have multiple submit buttons, one to save edits in progress and another to submit the completed form and move to the next step. The current app state was maintained server side and validation was often handled there save for some basic formatting client side JavaScript could handle.
This setup allowed even the most primitive frame-supporting browsers to use CRUD web apps. IIRC early web frameworks like WebObjects leaned into that model of web app.
They were horrible -- you'd hit the back button and only one of the frames would go back and then the app would be in an inconsistent state... it was a mess!
I don't love JavaScript monstrosities but XHR and dynamic HTML were a vast improvement over HTML forms and frame/iframe abuse.
Try some other architecture though and all bets were off.
Amazon's web store looked and worked mostly the same as it does now, people were very impressed with MapQuest, etc.
Applications like that can feel really fast, almost desktop application fast, if you are running them on a powerful desktop computer and viewing them on another computer or tablet over a LAN
https://docs.asciidoctor.org/asciidoc/latest/directives/incl...
I’m sure some purist argument has driven this somewhere.
All sorts of data could be linked together to display or remix by user agents.
This helps the creator, but not the consumer, right? That is, if I visit 100 of your static documents created with a template engine, then I'll still be downloading some identical content 100 times.
XSLT did exactly what HTML includes could do and more. The user agent could cache stylesheets or if it wanted override a linked stylesheet (like with CSS) and transform the raw data any way it wanted.
While it evaluated the xslt serverside it was a really neat and simple approach.
On the other hand it means less work for the client, which is a pretty big deal on mobile.
[0] https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Com...
That doesn't seem like a significant problem at all, on the consumer side.
What is this identical content across 100 different pages? Page header, footer, sidebar? The text content of those should be small relative to the unique page content, so who cares?
Usually most of the weight is images, scripts and CSS, and those don't need to be duplicated.
If the common text content is large for some reason, put the small dynamic part in an iframe, or swap it out with javascript.
If anyone has a genuine example of a site where redundant HTML content across multiple pages caused significant bloat, I'd be interested to hear about it.
To give you a concrete example, consider caching (or, equivalently, compiling) web pages. Maybe you have 100 articles, which share a common header and footer. If you make a change to the header, then all 100 articles have to be uncached/rebuilt. Why? Because somebody did not remove the duplication when they had the chance :-)
Actually, that was part of the original plan - https://caniuse.com/iframe-seamless
It worked rather like a reverse shadow DOM, allowing CSS from the parent document to leak into the child, removing borders and other visual chrome that would make it distinguishable from the host, except you still had to use fixed CSS layouts and resize it with JS.
Like writing a line of js?
If internally this gets optimized to a simple I/O operation (which it should) then why add the JS indirection in the first place?
That’s the reason it doesn’t get implemented. Nobody wants the simple I/O operation based inclusion. The moment you try to propose it, there’ll be demands to add conditional logic or macros. More relevant for the web is instantiating html templates, which will undoubtedly get piled onto such a feature. And pretty soon you have yet another:
> interpreter in your browser
Might as well use the one already there.
I do it in a way that doesn't stop the renderer.
A small 10KB lib that augments HTML with the essential good stuff (like dynamic imports of static HTML)
there are many examples of HTMX (since it is a self contained and tiny) being used alongside existing frameworks
of course for some of us, since HTMX brings dynamic UX to back end frameworks, it is a way of life https://harcstack.org (warning - raku code may hurt your eyes)
Depending on the specific objection to Javascript, this may or may not matter:
1. You object to any/all JS on a page? Yeah, then this won't work for you.
2. You object to having to write JS just to get client-side includes? This should mostly work for you.
It all depends on what the actual objection is.
https://github.com/bigskysoftware/fixi
My dialup ISP back then didn't disable using .htaccess files in the web space they provided to end users. That meant I could turn on server-side includes! Later I figured out how to enable CGI. (I even went so far as to code rudimentary webshells in Perl just so I could explore the webserver box...)
I still remember the script I wrote to replace thousands (literally) slightly different headers and footers in some large websites of the 90s. How liberating to finally have that.
https://developer.mozilla.org/en-US/docs/Web/API/Service_Wor...
https://github.com/jasoncartwright/clientsideinclude
And it is a genuinely good question!
I think the answer of PD says feels the truest.
JS/CSS with all its bureaucracy are nothing compared to HTML it seems. Maybe people don't find nothing wrong with Html, maybe if they do, they just reach out for js/css and try to fix html (ahem frontend frameworks).
That being said, I have just regurgitated what PD says has said and I give him full credit of that but I am also genuinely confused as to why I have heard that JS / CSS are bureaucratic (I remember that there was this fireship video of types being added in JS and I think I had watched it atleast 1 year ago (can be wrong) but I haven't heard anything for it and I see a lot of JS proposals just stuck from my observation
And yet HTML is such level of bureaucratic that the answer to why HTML doesn't have a feature is because of its bureaucracy. Maybe someone can explain the history of it and why?
Includes are a standard part of many document systems. Headers and footers are a perfect example - if I update a document I certainly don't want to update the document revision number on every single page! It also allows you to add navigation between documents in a way that is easy to maintain.
LaTeX can do it. Microsoft Word can do it (in a typically horrible Microsoftian way). Why not HTML?
If you disagree, and you think you are in the right, you probably have a somewhat good argument you can use in a reply.
The fact that you don't means my explanation makes sense.
Client side include feature for HTML
https://github.com/whatwg/html/issues/2791
What does this mean? This is a pure HTML solution, not just "technically" but in reality. (And before iframe there were frames and frameset). Just because the author doesn't like them don't make them non-existent.
An iframe is a window into another webpage, and is bounded as such both visually and in terms of DOM interfaces. A simple example would be that an iframe header can't have drop-down menus that overlap content from the page hosting it.
They are categorically not the same DX/UX as SSI et al. and it's absolutely bizarre to me that there's so many comments making this complaint.
They would be a lot more useful if we could write e.g. <iframe src=abc.html height=auto width=100> so the height of the iframe element is set by the abc.html document instead of the parent document.
Then you need a postMessage to send body size to parent frame which then needs to listen for messages and resize the iframe element.
As the article says, the problem is a solved one. The "includes" issue is how every web design student learns about PHP. In most CMSes, "includes" become "template partials" and are one of the first things explained in the documentation.
There really isn't any need to make includes available through just HTML. HTML is a presentation format and doesn't do anything interesting without CSS and JS anyway.
HTML is a markup language that identifies the functional role of bits of text. In that sense, it is there to provide information about how to present the text, and is thus a presentation format.
It is also a document description language, because almost all document description languages are also a presentation format.
Some content is already loaded asynchronously such as images, content below the fold etc.
> HTML is really just a markup syntax, not a programming language
flamebait detected :) It's a declarative language, interpreted by each browser engine separately.
> considered to be server-side
Good point! Wouldn't fetching a template partial happen the same way (like fetching an image?)
<html src="/some/page.html">, <div src="/some/div.html">, <span src="/some/span.html">, etc.
Or create a new tag that's a noun like fragment, page, document, subdoc or something.
Surely that's no less markup than svg, img, script, video, iframe, and what not.
I always assumed it stood for my initials.
Nor is this something unique to SGML. XML is also a "markup language", yet XInclude is a thing.
touchay!!
That's not an argument that client-side includes shouldn't happen. In fact HTML already has worse versions of this via frames and iframes. A client-side equivalent of a server-side include fits naturally into what people do with HTML.
https://github.com/benstigsen/include.js
Exactly! Include makes perfect sense on server-side.
But client-side include means that the client should be able to modify original DOM at unknown moment of time. Options are
1. at HTML parse time (before even DOM is generated). This requires synchronous request to server for the inclusion. Not desirable.
2. after DOM creation: <include src=""> (or whatever) needs to appear in the DOM, chunk loaded asynchronously and then the <include> DOM element(sic!) needs to be replaced(or how?) by external fragment. This disables any existing DOM structure validation mechanism.
Having said that...
I've implemented <include> in my Sciter engine using strategy #1. It works there as HTML in Sciter usually comes from local app resources / file system where price of issuing additional "get chunk" request is negligible.
See: https://docs.sciter.com/docs/HTML/html-include
> the problem is a solved one
is a sure-fire way to know that a problem is not solved
It's "solved" only in the sense that you need to use a programming language on the server to "solve" it. If all you are doing is static pages, it's most definitely not solved.
One drawback though would be that one indeed would have to maintain dependencies, which would be error prone beyond simply adding headers and footers... I wonder if one could (ab)use CPP [1] and its -M option to do that.
[1] https://gcc.gnu.org/onlinedocs/cpp/Invocation.html
An additional request is another round trip. That can be very slow. Average TTFB on the internet in the US is ~0.7 seconds.
It's much faster to send it as part of the same request as you then don't have to wait for the browser to discover it, request it, wait for the response and then add it.
A build process does not have to be complicated, at all. If you can write HTML then using something that can simply read the HTML includes you wish existed and swap it with the specified filename is trivial.
Ofc, the idea has many other issues, like how to handle dependencies of the included HTML, how to handle conflicts, what oath to use and many more.
That's "using a programming language to solve the problem", isn't it?
> It's way cheaper as you do the work once, instead of every client being much slower because they have to do additional requests.
What work do client-side includes have to do other than fetching the page (which will get cached anyway)? It's less work to have a `<include-remote ...>` builtin than even a simple Makefile on the server.
Fetching another resource is expensive. It's another round trip, and depending on many factors it could be another second to load the page. And if the HTML includes other nested HTML then it can be much slower.
This is the exact thing we try to avoid when building websites that perform well. You want as few chained requests as possible, and you want the browser to be aware of them as soon as possible, with the correct priority. That way the browser can get the important stuff needed to display content fast.
Including HTML client side for templating is just wasteful, slow and dumb from a technical standpoint.
Every client would have to do another request for each include. It would literally be many thousands of times slower(or worse) than doing it locally where the templates can be in memory as you render the pre-render the pages. You also save a ton of CPU cycles and bandwidth, by not serving more files with additional overhead like headers.
Yeah, it's not. I'm doing client side includes and the includes get cached by the browser. I'm sure I would have noticed if my pages went from 1s to display to 1000s to display.
If you have a site/webapp with (say) twenty pages, that's only two extra requests for both header and footer.
There was a lot of criticism for frames [1] but still they were successfully deployed for useful stuff like Java API documentation [2].
In my opinion the whole thing didn't stay mostly because of too little flexibility for designer: Framesets were probably well enough for useful information pages but didn't account for all the designers' needs with their bulky scrollbars and limited number of subspaces on the screen. Today it is too late to revive them because framesets as-is wouldn't probably work well on mobile...
[1] <https://www.nngroup.com/articles/why-frames-suck-most-of-the...> - I love how much of it is not applicable anymore and all of these problems mentioned with frames are present in today's web in an even nastier way?
[2] <https://www.eeng.dcu.ie/~ee553/ee402notes/html/figures/JavaD...>
Of course "back then" this was an important feature and one of the reasons for getting rid of frames :)
The actual term include is an XML feature and it’s that feature the article is hoping for. HTML had an alternate approach that came into existence before XML. That approach was frames. Frames did much more than XML includes and so HTML never gained that feature. Frames lost favor due to misuse, security, accessibility, and variety of other concerns.
I still like to use them occasionally but it incurs a "compilation" step to evaluate them prior to handing the result of this compilation to the users/browsers.
XML includes are blocking because XSL support hasn't been updated for 25 years, but there's no reason why we couldn't have it async by now if resources were devoted to this instead of webusb etc.
You'd better not jinx it: XSL support seems like just the sort of thing browser devs would want to tear out in the name of reducing attack surface. They already dislike the better-known SVG and never add any new features to it. I often worry that the status quo persists only because they haven't really thought about it in the last 20 years.
I’ve used XSLT in anger - I used it to build Excel worksheets (in XML format) using libXSLT. I found it very verbose and hard to read. And Xpath is pretty torturous.
I wish I could have used Javascript. I wish Office objects were halfway as easy to compose as the DOM. I know a lot of people hate on Javascript and the DOM, but it’s way easier to work with than the alternatives.
The logic is performed elsewhere. If you were to have includes directly in HTML, it means that browsers must implement logic for HTML. So it is not 'just' a parser anymore.
Imagine for example that I create an infinite loop of includes, who is responsible to limit me? How to ensure that all other browsers implement it in the same way?
What happens if I perform an injection from another website? Then we start to have cors policy management to write. (iframes were bad for this)
Now imagine using Javascript I inject an include somewhere, should the website reload in some way? So we have a dynamic DOM in HTML?
Client-side includes are not "processing". HTML already has frames and iframes which do this, just in a worse way, so we'd be better off.
(yes in my view I interpret includes as a basic procedure)
[1] http://www.info.ucl.ac.be/people/PVR/paradigmsDIAGRAMeng201....
https://en.wikipedia.org/wiki/Transclusion
We can probably copy the specs for <frameset> and deal with it the same way:
https://www.w3.org/TR/WD-frames-970331#:~:text=Infinite%20Re...
> How to ensure that all other browsers implement it in the same way?Browsers that don't implement the specs will eventually break:
https://bugzilla.mozilla.org/show_bug.cgi?id=8065
* the actual existence of frames (although those are deprecated)
* iframes (which are not deprecated, so seemingly doing declarative inclusion of HTML in HTML was not what was wrong with frames)
* imports in CSS, which share some of the same problems / concerns as HTML imports
* the existence of JavaScript with its ability to change anything on the page, including the ability to issue HTTP requests and be written arbitrarily obfuscated ways.
https://en.wikipedia.org/wiki/Transclusion
It was part of Project Xanadu, and originally considered to be an important feature of hypertext.
Notably, mediawiki uses transclusion extensively. It sometimes feels like the wiki is the truest form of hypertext.
it never quite took off
In Xanadu you could transclude just an excerpt from one document into another document.
If you wanted to do this with HTML you need an answer for the CSS. In any particular case you can solve it, making judgements about which attributes should be consistent between the host document, the guest document and the guest-embedded-in-host. The general case, however, is unclear.
For a straightforward <include ...> tag the guest document is engineered to live inside the CSS environment (descendant of the 3rd div child of a p that has class ".rodney") that the host puts it in.
Another straightforward answer is the Shadow DOM which, for the most part, lets the guest style itself without affecting the rest of the document. I think in that case the host can still put some styles in to patch the guest.
I wish I would have advocated more for it though. I think it would be pretty easy to add using a new attribute on <script> since the parser already pauses there, so making something like <script transclude={url}> would likely not be too difficult.