This allows us to define a new piece of functionality in our web app in a simple, modular and isolated way. It even allows a sort of poor-man's scoping for CSS — just prefix every selector with #settingsDialog and you know it will only apply within that dialog. We also have a mini dialog framework that handles moving the <dialog> element to the main document, displaying it, running transitions, handling OK/Cancel and so on.

This approach is rolled out over the entire app. It's so effective, we use it everywhere. Each separate pane in the main view has its own import. The main menu has its own import. The account component lives in an import. Each kind of object in the game development IDE (which we call a Plugin) is defined in its own import. It covers everything, because it's so simple, intuitive and effective.

Surprisingly, it even covers pure-script components like the data model as well. HTML imports have built-in deduplication, preserve order of execution, can load asynchronously, and are easy to parse and concatenate in a build process. If we started today we'd probably choose JavaScript Modules for these components, but mainly just to avoid having to share top-level names in the global namespace. Other than that, HTML imports actually provide very good script componentisation too.

What's the alternative? Even if you use JavaScript Modules, where do you define a new dialog? Are you supposed to wedge it in the middle of thousands of lines of markup in a single HTML file that covers everything? Are you meant to have hundreds of link tags for CSS in your <head> that take forever to scroll through? Some languages let you wedge bits of markup inside JavaScript itself, such as with JSX, but I strongly dislike this development pattern. Such languages are non-standard, require an extra compile step, and moving large amounts of markup in to script bloats script files, slows down parsing and startup time, mixes instead of separates concerns, and is harder to write tooling for since you have a script-markup mish-mash. Shouldn't markup stay in HTML files?

What about other Web Components?

We make minimal use of all other components. Perhaps it might make our code a bit cleaner in some cases, or be more academically correct/modular, but we get by easily enough. Here's a quick run-down of what else we use:

Custom Elements : we don't use this beyond custom tag names, like <dialog-caption> in the previous example. I think our architecture is best described as Model-View-ViewModel (MVVM). So they are probably not particularly relevant to us since we tend to have JavaScript classes owning DOM elements. Custom Elements appears to use the reverse — DOM elements owning a JavaScript class. I guess both ways can work; MVVM works fine for us though.

: we don't use this beyond custom tag names, like <dialog-caption> in the previous example. I think our architecture is best described as Model-View-ViewModel (MVVM). So they are probably not particularly relevant to us since we tend to have JavaScript classes owning DOM elements. Custom Elements appears to use the reverse — DOM elements owning a JavaScript class. I guess both ways can work; MVVM works fine for us though. HTML Templates : these are handy for stamping out a chunk of DOM repeatedly. I counted, and we use the template element exactly four times in our entire app. So a nice thing to have around, but hardly critical infrastructure in our case.

: these are handy for stamping out a chunk of DOM repeatedly. I counted, and we use the template element exactly four times in our entire app. So a nice thing to have around, but hardly critical infrastructure in our case. Shadow DOM: we don't use this at all. I'd guess this is much more applicable if you actually use Custom Elements, or if you're developing isolated components intended for third-party use in a library. We developed our own UI library because none existed that did what we needed (open Construct 3 and you should see what I mean), so this again this kind of isolation isn't particularly important since it's generally all our own code and markup. If we rewrote our whole UI library, I might experiment with this though.

Part of developing Construct 3 involved designing our own comprehensive UI library. This covers a windowing system (of which dialogs are a subset), tabs, toolbars, icons, menus, notifications and tips, tree controls, icon view controls, table controls, property grids and more. Custom Elements and Shadow DOM could potentially make these more modular, but we've come this far and it's worked fine, so these do not seem to be critical components for a large web app. That contrasts with HTML Imports, which are fundamental to the overall architecture.

I must add that I don't at all assume that everyone develops web apps like us. I am sure that for other kinds of app, these other web components will be critical. That's fine, and this is not meant to dismiss these as unnecessary technologies. My point is to emphasise that in at least some cases, HTML imports are by far the most important of the set.

What went wrong for HTML imports?

Basically, I think HTML imports are ahead of their time.

We started development of Construct 3 about three years ago. Before that we actually made a prototype even further back, using the traditional block layout, used jQuery, and so on. The prototype was so obviously going to be a huge mess with that approach that we decided we'd have to bet on all the modern web platform features for it to be feasible. Construct 3 uses to name but a few: CSS Grid, CSS variables (aka custom properties), CSS Containment (also critical for layout performance), the Dialog element, Service Worker, WebGL and WebGL 2, Web Animations, and more. Notice many of these features only recently became available even in just Chrome. In other words, web apps on the scale of Construct 3 have only just become feasible to release. HTML Imports were first released in Chrome 36 in mid-2014. That was just too soon for many web apps of Construct 3's scale to be around.

Meanwhile, Google appears to have been putting the most resources in to browser development of all the browser makers. Other browsers are generally playing catch-up, and have a wide array of APIs to consider implementing with limited resources. Understandably they are conservative. Ideally they want to see developer demand and widespread usage of an API so they know it's important it's implemented, but this creates something of a chicken-and-egg situation if they hesitate. Other vendors take a "wait-and-see" approach. In particular some browsers wanted to see how JavaScript Modules play out and how they will interoperate with imports — and Modules are still only just on the cusp of being supported. By now all this postponing from other browser makers has probably put off developers who want to see features with cross-browser support.

Finally, as outlined above, I think one of the best use cases for HTML imports is with dialogs. However the <dialog> element itself is still currently only supported in Chrome. So this feature which is a particularly compelling case for imports has no cross-browser support either. This probably also reduces the perceived utility of imports.

However it's now been so long, the Chrome team (and some other browser makers) appear to be taking the view that it's a failed feature. I hope this blog post helps counter that perception, and demonstrate the real utility of the feature.

Why not polyfill it?

We can, and do. However the main reason is performance. Browsers are good at parsing HTML and can start resource fetches ahead of the time they're actually needed. Consider this case: