Appearance
HTML Includes
Include HTML component files at runtime using a custom <html-include> element. A processIncludes function queries the document for include elements, loads their components in parallel, and removes the include elements after loading. The module auto-processes includes on DOMContentLoaded.
When to use
Use HTML includes when you need to compose pages from separate component files at runtime. Each component lives in its own .html file and loads in parallel without a bundler. Declare includes in markup and they load automatically, making this ideal for prototyping and reusable HTML fragments.
The pattern
Declaring includes
Add <html-include> elements with a src attribute pointing to each component file. They load their components in parallel and remove themselves from the DOM when finished.
html
<!DOCTYPE html>
<html>
<head>
<script type="module" src="./wck.js"></script>
</head>
<body>
<!-- These elements load their components and
then remove themselves from the DOM -->
<html-include
src="./my-counter.component.html"
></html-include>
<html-include
src="./ui-icon.component.html"
></html-include>
<!-- Use the loaded components -->
<my-counter></my-counter>
<ui-icon name="check"></ui-icon>
</body>
</html>Programmatic usage
In test or script code, call processIncludes manually and wait for components to be defined before interacting with them.
javascript
import {
processIncludes, componentsReady,
} from "./wck.js";
await processIncludes();
await componentsReady("my-counter", "ui-icon");The processIncludes implementation
The processIncludes function finds all <html-include> elements with a src attribute, loads each component in parallel using loadComponent, and removes the include element from the DOM once its content has been injected.
javascript
export async function processIncludes() {
const includes =
document.querySelectorAll("html-include[src]");
const promises = [];
for (const include of includes) {
const src = include.getAttribute("src");
if (src) {
promises.push(
loadComponent(src).then(() => {
include.remove();
})
);
}
}
await Promise.all(promises);
}The module auto-processes includes so pages don't need an explicit call. If the document is still loading it waits for DOMContentLoaded; otherwise it runs immediately.
javascript
if (document.readyState === "loading") {
document.addEventListener(
"DOMContentLoaded",
processIncludes,
);
} else {
processIncludes();
}How it works
processIncludesqueries for allhtml-include[src]elements in the document.- For each element, it calls
loadComponent(src)which fetches the HTML file, parses it, and injects templates, styles, and scripts into the document. - After loading completes, the
<html-include>element removes itself from the DOM, leaving only the injected content. Promise.allensures all components load in parallel rather than sequentially.
Trade-offs
- Parallel loading. All includes load simultaneously via
Promise.all. This is faster than sequential loading but means load order is non-deterministic. If components depend on each other, usecomponentsReadyto wait. - Self-cleaning. Include elements remove themselves after loading, so the final DOM contains only the injected templates, styles, and scripts — no leftover include markers.
- Valid custom element name.
html-includecontains a hyphen, making it a valid custom element name that will not collide with native HTML elements. The browser treats it as an unknown element until processed. - No shadow DOM. Components inject into the light DOM (templates to body, styles to head). There is no style encapsulation, but global styling just works.
- Standards-based alternative. For a more standards-aligned approach, see html-include-element which uses the same declarative pattern with additional features.