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; seamless never 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.