A polyfill supplies a web feature where a browser lacks native support. For Web Components, the first question is which feature is missing: Custom Elements, Shadow DOM access, and Shadow DOM CSS do not have the same compatibility story. section 2.7 section 8.3
Choose the smallest compatibility measure that fits the feature:
- For Custom Elements, include the custom-elements polyfill as a page script, either from a downloaded package or a CDN. This is presented as a drop-in measure for browsers without Custom Elements support. section 2.7 section 12.1
- For broader Web Components support, the webcomponentsjs package offers feature detection and fills in unsupported features, including Custom Elements and Shadow DOM. section 8.3
- For Shadow DOM, distinguish DOM access from CSS isolation. ShadyDOM can address access to the component’s DOM; ShadyCSS helps with CSS, but needs more integration than a drop-in script. section 8.3 section 10.3
Use the Custom Elements polyfill
Add `<script src="https://unpkg.com/@webcomponents/custom-elements"></script>` to a page that loads a custom-element component. This handles missing Custom Elements support; it does not make unsupported JavaScript syntax work. Older browsers such as IE11 may also need ES2015/ES6 code transpiled to ES5. section 12.1 section 2.7
A polyfill is not always the best fallback. Shadow DOM CSS isolation is difficult to emulate, and its polyfills can have limitations that component code must accommodate. One alternative is to use Shadow DOM when available and render into the element itself otherwise; that choice also requires adapting DOM lookups and CSS selectors. section 10.3 section 12.1
Listing 12.2. Enabling a Shadow DOM toggle
constructor() {
super();
if (Slider.USE_SHADOWDOM_WHEN_AVAILABLE && #1
this.attachShadow) {
this.root = this.attachShadow({mode: 'open'});
} else {
this.root = this;
}
document.addEventListener('mousemove', #2
e => this.eventHandler(e));
document.addEventListener('mouseup', e => this.eventHandler(e));
this.addEventListener('mousedown', e => this.eventHandler(e));
}
connectedCallback() {
if (!this.initialized) { #3
this.root.innerHTML = Template.render({ #4
useShadowDOM: Slider.USE_SHADOWDOM_WHEN_AVAILABLE &&
this.attachShadow });
this.dom = Template.mapDOM(this.root);
this.initialized = true;
if (this.backgroundcolor) { #5
this.setColor(this.backgroundcolor);
}
if (this.value) {
this.refreshSlider(this.value);
}
}
}
The component checks for `attachShadow`, then selects either a shadow root or the element itself as its rendering root. The rendered template receives the same choice so its output can follow the selected mode. section 12.1
HTML Imports show another limit: a polyfill can keep a workflow feasible even when the feature itself is deprecated. The import polyfill is loaded before a `<link rel="import">`, but HTML Imports never gained broad browser adoption. section 7.1

