Polyfills and Transpilation for Your Custom Elements

We covered the basics of creating custom elements using Web Component specs, but at the end we hinted that our simple custom element was not yet production-ready because of the use of new JavaScript features and the fact that Custom Elements and Shadow DOM are not supported in all popular browsers yet.

In this post, we’ll quickly go over the steps to transpile your custom element code to be compatible with ES5 and to include the necessary Web Components polyfills.


Your custom element code will contain ES6 classes and will probably also contain string literals and arrow functions. These features are great to use at author-time, but the code has to be transpiled using a tool like Babel so that it can run in browsers that only understand ES5 code. We’ll go ahead and use babel-cli and the babel-preset-es2015 preset do to just that.

If your project doesn’t have a package.json file just yet, go ahead an create one using either npm or Yarn. This will allow you to install the necessary packages.:

$ npm init

# or, using Yarn
$ yarn init

Once this is done, you can go ahead and install the necessary packages:

$ npm install babel-cli babel-preset-es2015 --save-dev

# or, using Yarn
$ yarn add babel-cli babel-preset-es2015 --dev

We’ll output our transpiled code into a dist folder, so you can go ahead and create that folder at the root of your project. Now you can add a build script to your package.json file that runs Babel with the es2015 preset and outputs the result in the dist folder:


  "name": "my-title",
  "version": "0.0.1",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "build": "babel --presets es2015 my-title.js --out-file dist/my-title.js"
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-preset-es2015": "^6.24.1"

Now you can go ahead and run the transpilation:

$ npm run build

# or, using Yarn
$ yarn build


Polyfills are small plugins that implement a feature to replace a missing native implementation for browsers that don’t have support yet. For Web Components, we’ll need polyfills for Custom Elements, Shadow DOM and the template element. Luckily for us WebComponents.org maintains a suite of polyfills that makes it easy to include the needed polyfills in your projects.

The suite provides a set of ready-made bundles to choose from. For example, the webcomponents-lite.js bundle, which polyfills HTML imports, Custom Elements, Shadow DOM (with polyfills called Shady DOM and Shady CSS) and the template element. That bundle will ensure that your custom elements will work all the way back to Internet Explorer 11.


There’s also a loader available, webcomponents-loader.js, that will perform some feature detection and include the necessary polyfills on the fly. Using the loader is probably the simplest way to get everything working, and this is what we’ll use here for our example.

Custom elements need to be defined using ES6 classes that extend HTMLElement, but now we’re using transpiled code that has the class syntax stripped away. We’ll need to use a file called custom-elements-es5-adapter.js to fix that for us.

At the time of this writing, webcomponents-loader.js should installed via Bower, so you'll want to make sure you have Bower available by running npm install -g bower.

Simply install the webcomponentsjs package into your project using Bower. This will install the necessary files in the bower_components folder:

$ bower install --save webcomponents/webcomponentsjs

Now, in your page’s head, include custom-elements-es5-adapter.js and webcomponents-loader.js:

index.html (partial)

<script src="bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
<script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>

The final step is only include the script for your transpiled custom element when the WebComponentsReady event fires. That’s a custom event that gets fired by the loader when the necessary polyfills have been loaded. We’ll simply create a script element, set its src property to the path of our transpiled custom element code and append it to the document’s head:

window.addEventListener('WebComponentsReady', function () {
  var myTitleScript = document.createElement('script');
  myTitleScript.src = 'dist/my-title.js';

Here’s how our final index.html file looks like:


<!DOCTYPE html>
<html lang="en">

  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Custom Element!</title>

  <script src="bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
  <script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>


    window.addEventListener('WebComponentsReady', function () {
      var myTitleScript = document.createElement('script');
      myTitleScript.src = 'dist/my-title.js';


🔧 And done! Your custom element is now ready to be included in your production projects.

✖ Clear

🕵 Search Results

🔎 Searching...