When building Web Components with Polymer CLI and serving it by running polymer serve it works fine on demo. Even on legacy browsers like IE11. But it may fail to work when included and used in a web project with more advanced context.

The main reason why this happens is Polyfills. Web Components built with Polymer works well on modern browsers which supports Custom Elements and ShadowDOM out of the box. But for legacy browsers, we have to polyfill those missing features.

In development mode, Polymer CLI automatically detects which polyfills browser requires and serves them on the fly. It also compiles the custom element’s ES6 class to ES5 compatible JavaScript at runtime.

To make the component work in our project we must do some extra work and compile the ES6 code to ES5 before we serve it. This is how I’m doing it.

First, configure polymer.json to instruct polymer build to compile ES5 of your component.

The following configuration of build section in polymer.json allows us to compile ES5 compatible code. Also, I set bundle:true which will bundle components and their dependencies into a single file. Without bundle:true component’s dependencies will be loaded separately which will make the component break on IE11

...
"build": [{
"name": "es5-bundle",
"bundle": true,
"js": {
"compile": true,
"minify": false
}
}]
...

From my personal experience, I would have just a single build configuration and serve the same JavaScript to all browsers despite the support of Custom Elements and ShadowDOM. This will put the built files into build/es5-bundle directory.

Set minify:false to make it easier to debug in browser the single-generated polymer component's file, because it won't be minified.

Next, load all the necessary bootstrap code to run the web component.

Following scripts should be added to your web projects HTML within <head> or before closing </body> tag.

<script type="text/javascript" src="build/es5-bundle/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
<script type="text/javascript" src="https://unpkg.com/[email protected]/lib/babel-helpers.min.js"></script>
<script type="text/javascript" src="build/es5-bundle/bower_components/webcomponentsjs/webcomponents-loader.js"></script>

We have included following files:

  • custom-elements-es5-adapter.js — ironically but after we have compiled the code to ES5 we need to include a small polyfill for browsers supporting ES6. This allows to run to ES5 compiled custom elements on browsers that support native custom elements.
  • babel-helpers.min.js — we need this for IE11 and Edge to support such a ES6 features as Symbol()
  • webcomponents-loader.js — this loader performs client side feature detection and requests only needed polyfills. E.g., for IE11 it will load webcomponents-lite.js which includes full list of polyfills. But for Edge webcomponents-hi-ce-sd.js which contains polyfills for HTML Import, Custom Element and ShadowDOM

Finally, append your component's HTML to DOM after WebComponentsReady event is fired by webcomponents-loader.js.

Make sure you load your Web Component after all polyfills are loaded and webcomponents-loader.js has done its job and raised WebComponentsReady event.

window.addEventListener('WebComponentsReady', () => {
let link = document.createElement('link');
link.setAttribute('rel', 'import');
link.setAttribute('href', `build/es5-bundle/my-component.html`);
document.getElementsByTagName('head')[0].appendChild(link)
});

You can add this event listener in a separate JS file and include it before webcomponents-loader.js to import your component and make it available in the HTML as soon as the Web Components are bootstrapped.