Why can't HTML alone do includes?
Scope of the problem: what “HTML includes” would mean
- Desire: a simple, declarative way to reuse fragments like headers/footers/navigation across pages (e.g.
<include src="header.html">) without JS, build tools, or a dynamic server. - Current native options (
<iframe>,<frame>,<object>) are seen as “HTML includes” only in a very rough sense: they embed entire documents, not fragments, and behave like separate pages.
Why existing HTML mechanisms are considered insufficient
- Iframes / frames / object
- Separate DOM, origin and navigation; poor for unified layout, dropdown menus, overlays, or accessible, single-page experiences.
- Hard to size: no “height: auto by content,” leading to nested scrollbars or fragile postMessage hacks;
seamlessnever solved it. - Framesets/iframes break deep-linking, browser navigation, caching expectations, and are widely viewed as bad UX despite solving the “static header” problem.
- Server-side includes / templating / static site generators
- Technically solve DRY headers/footers, but require a server or build step; not ideal for simple static hosting or “just HTML on disk.”
- Don’t help the consumer cache fragments across pages; every page ships repeated markup.
- JS-based solutions (htmx, custom elements, small snippets)
- Work well but require JavaScript, which some explicitly want to avoid or minimize.
- Behavior is opaque to static tools (archivers, indexers) and not standardized.
Historical and standards context
- HTML started as a hypertext document format: link whole documents, not compose fragments. Many argue includes were “assumed server-side.”
- SGML and XML had entity-based includes and XInclude; XHTML and XSLT/XPath could have supported fragment reuse, but that ecosystem never became mainstream.
- HTML Imports (as part of early Web Components) briefly existed in some browsers but were dropped: considered complex, underused, overlapping with ES modules, and not quite a simple “#include.”
- A long‑running WHATWG issue on client-side includes highlights spec concerns:
- Extra round-trips and parser stalls (breaking streaming parse/render).
- CORS/security and XSS‑style problems.
- Relative URL resolution, CSS/ID collisions, circular includes, and DOM validation.
Philosophical disagreements
- One side: HTML is markup, not a programming language; logic like includes belongs on the server or in JS.
- Other side: “include another document” is itself markup, akin to
<img>,<script>,<link>; transclusion is core hypertext, and the lack of a standard include has spawned countless ad‑hoc solutions. - Some believe demand is too small (few people hand-write HTML now); others argue the persistence of frameworks, SSIs, and libraries proves the opposite.
Workarounds people actually use
- Server Side Includes, Caddy templates, static generators, or PHP-like includes.
- XSLT/XHTML pipelines or XML+XSLT in the browser for templating.
- Minimal JS: custom elements like
<html-include href="...">, self‑replacing<script>tags, service worker–based composition. - SVG
<use>and<object>/<iframe>in constrained scenarios.