Web Components Template Polyfill

A minimal polyfill that backfills the native HTML template element for browsers without HTMLTemplateElement support.

Library
npm
v1.5.1
1,190stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
51/100Fair
Development Activity20
Maintenance0
Community84
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
59/100Fair
Architecture65
Code Quality62
Innovation75
Learning Curve35

@webcomponents/template is a small, standalone polyfill for the HTML <template> element, published from the webcomponents/polyfills monorepo alongside the custom-elements and shadydom polyfills that make up the broader Web Components polyfill suite. It exists purely to backfill the DOM API surface — HTMLTemplateElement, template.content, and correct cloning/importing semantics — that older browsers like IE11 never implemented natively.

Rather than reinventing browser behavior, the polyfill intercepts a handful of DOM entry points — document.createElement, Node.prototype.cloneNode, Document.prototype.importNode, and HTMLElement.prototype.innerHTML — and layers in the missing template-decoration and content-fragment behavior only when the native feature is absent. It’s designed to load first and coexist safely underneath libraries like Custom Elements v1, ShadyDOM, LitElement, and the Polymer Library, which all assume a working <template> element exists before they run.

What You Get

  • Standalone template.js file - a single, dependency-free script you can drop in before your app code, no build step required.
  • Feature-detected activation - the polyfill only patches DOM prototypes when HTMLTemplateElement is genuinely missing, so it’s effectively a no-op in modern browsers.
  • Correct content-fragment semantics - implements template.content as a real DocumentFragment, including nested <template> cloning and IE11 document-fragment bug workarounds.
  • Auto-bootstrapping - templates already present in the main document are decorated automatically on DOMContentLoaded, and new ones via document.createElement('template') are decorated on creation.
  • TypeScript externs - ships a .d.ts file declaring the HTMLTemplateElementConstructor.bootstrap() global for typed consumers.

Common Use Cases

  • Supporting IE11 users - apps built with Custom Elements/Shadow DOM that still need to run in Internet Explorer 11 load this polyfill first to get a working <template> element.
  • Loading it via the webcomponentsjs bundle - most consumers install @webcomponents/webcomponentsjs, which bundles this polyfill together with custom-elements and shadydom behind a feature-detecting loader.
  • Powering Polymer/LitElement apps on legacy browsers - the Polymer Library and early LitElement releases depend on a real <template> element and pull this polyfill in transitively for older-browser support.
  • Embedding widgets in third-party pages - widget authors who can’t control the host page’s browser support matrix include this polyfill defensively.

Under The Hood

Architecture The module is a single IIFE with no exports, structured as sequential feature-detection guards (needsTemplate, needsCloning, needsDocFrag) that conditionally patch DOM prototypes — Document.prototype.createElement, Node.prototype.cloneNode/appendChild/insertBefore/replaceChild, Document.prototype.importNode, DOMParser.prototype.parseFromString, and HTMLElement.prototype.innerHTML — rather than exposing a conventional module API. PolyfilledHTMLTemplateElement acts as the central object holding decorate/bootstrap/_cloneNode static methods that every patched entry point funnels through, and native DOM operations are captured once at load time (capturedCloneNode, capturedAppendChild, etc.) so the polyfill’s own internal work doesn’t retrigger its own patches. Any consumer relying on template.content being a real DocumentFragment — the Custom Elements polyfill, ShadyDOM, LitElement, Polymer — breaks immediately if this decorate/bootstrap flow changes, since they all assume it runs first and unconditionally.

Tech Stack Vanilla, dependency-free JavaScript with no runtime dependencies declared in package.json. Build tooling is Gulp plus Google Closure Compiler in ADVANCED mode, compiling the ES6-authored source down to ES5 and emitting template.min.js with sourcemaps; the surrounding monorepo (ten sibling polyfill packages) is orchestrated by Lerna for versioning and bootstrap. Types are expressed via Closure Compiler JSDoc annotations rather than TypeScript, though a hand-written template.d.ts extern ships for TypeScript consumers. Linting runs through ESLint (with the TypeScript-ESLint parser applied even to JS) and Prettier, enforced pre-commit via Husky and lint-staged.

Code Quality There are no conventional unit test files for this package; correctness is instead validated through browser HTML fixtures (basic.html, document-fragment.html, runner.html) executed via web-component-tester, an appropriate style for a DOM-patching polyfill whose behavior only manifests through real DOM interaction, backed by a Sauce Labs CI matrix covering legacy targets like IE11 and older Safari/Edge. Error handling is intentionally minimal — the polyfill either silently no-ops via feature detection or lets native DOM exceptions propagate, with one explicit thrown error when outerHTML is set on a parentless template, mirroring native behavior. Naming is consistent and self-documenting, and CI enforces lint and formatting on every push.

API Design There’s effectively zero public API surface by design: loading template.js makes the global HTMLTemplateElement, template.content, and cloneNode behavior simply work like the native spec, with no configuration object, initialization call, or module exports to learn. The one visible extension point, HTMLTemplateElementConstructor.bootstrap(), is documented through the shipped .d.ts extern for the advanced case of manually rescanning a subtree for undecorated templates after third-party innerHTML injection. Adoption boilerplate is a single script tag (or the bundled webcomponentsjs loader when combined with sibling polyfills) — about as close to invisible, zero-config integration as a polyfill can offer.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search