The webcomponents-loader.js provides intelligent feature detection and dynamic loading of only the necessary polyfill bundles, optimizing performance and reducing payload size.
Main entry point that detects browser capabilities and loads appropriate polyfill bundles.
/**
* Include webcomponents-loader.js as a script tag
* The loader automatically detects which polyfills are needed and loads them
*/
// <script src="webcomponents-loader.js"></script>
// After loading, global WebComponents object becomes available
interface WebComponents {
/** Boolean indicating if polyfills are loaded and ready */
ready: boolean;
/** Optional root path for loading polyfill bundles */
root?: string | TrustedScriptURL;
/** Register callback to run after polyfills load (async only) */
waitFor(callback: WaitForCallback): void;
/** Internal method for batching custom element upgrades */
_batchCustomElements(): void;
}Usage Examples:
<!-- Synchronous loading -->
<script src="webcomponents-loader.js"></script>
<script type="module" src="my-element.js"></script>
<!-- Asynchronous loading -->
<script src="webcomponents-loader.js" defer></script>
<script type="module">
WebComponents.waitFor(() => import('./my-element.js'));
</script>Registers callbacks to execute after polyfills are loaded when using asynchronous loading.
/**
* Register callback to run after polyfills load (async loading only)
* @param callback - Function to execute, can return a Promise
*/
waitFor(callback: () => void | Promise<any>): void;
type WaitForCallback = () => void | Promise<any>;Usage Examples:
// Simple callback
WebComponents.waitFor(() => {
console.log('Polyfills ready!');
});
// Async callback that loads modules
WebComponents.waitFor(async () => {
if (!window.fetch) {
await import('whatwg-fetch');
}
return import('./my-element.js');
});
// Multiple callbacks (processed in order)
WebComponents.waitFor(() => import('./element-a.js'));
WebComponents.waitFor(() => import('./element-b.js'));Configures the base path for loading polyfill bundles when inlining the loader or using custom deployment paths.
/**
* Optional root path for loading polyfill bundles
* Must be set before the loader script runs
* When using Trusted Types, should be a TrustedScriptURL
*/
interface WebComponents {
root?: string | TrustedScriptURL;
}Usage Examples:
<!-- Set root path for custom deployment -->
<script>
window.WebComponents = window.WebComponents || {};
window.WebComponents.root = '/assets/webcomponents/';
</script>
<script src="inline-webcomponents-loader.js"></script>
<!-- With Trusted Types -->
<script>
window.WebComponents = window.WebComponents || {};
// Assume policy is a TrustedTypePolicy
window.WebComponents.root = policy.createScriptURL('/assets/webcomponents/');
</script>The loader performs automatic detection of browser capabilities to determine which polyfills to load.
Detected Features:
attachShadow and getRootNode in Element.prototypewindow.customElements APIHTMLTemplateElement with proper content property and cloningPromise, Array.from, URL, Symbol constructorsOverride Options:
// Force ShadyDOM polyfill even if native Shadow DOM is available
window.ShadyDOM = { force: true };
// Force Custom Elements polyfill even if native implementation exists
window.customElements = { forcePolyfill: true };The loader selects bundles based on detected features:
For Content Security Policy compliance with Trusted Types:
/**
* CSP Trusted Types support
* Allow 'webcomponents-loader' policy name in CSP header
*/
// CSP Header example:
// Content-Security-Policy: trusted-types webcomponents-loader;
// The loader automatically creates and uses a trusted types policy
// No additional configuration needed unless setting WebComponents.rootUsage with Custom Root:
// WebComponents.root should be a TrustedScriptURL when using Trusted Types
const policy = trustedTypes.createPolicy('my-policy', {
createScriptURL: (url) => url
});
window.WebComponents = {
root: policy.createScriptURL('/assets/webcomponents/')
};Loader runs immediately when encountered, uses document.write() for bundle injection.
<!-- Synchronous mode -->
<script src="webcomponents-loader.js"></script>
<!-- Custom elements scripts can be loaded immediately after -->
<script type="module" src="my-element.js"></script>Loader runs after DOM is ready, requires waitFor() for dependent scripts.
<!-- Asynchronous mode -->
<script src="webcomponents-loader.js" defer></script>
<script type="module">
WebComponents.waitFor(() => {
// Guaranteed that polyfills are ready
return import('./my-element.js');
});
</script>// Listen for loading errors
const script = document.createElement('script');
script.src = 'webcomponents-loader.js';
script.addEventListener('error', () => {
console.error('Failed to load Web Components polyfills');
});Bundle loading errors are thrown as JavaScript errors with descriptive messages indicating the failed bundle URL.