Search code examples
javascripthtmlcsstemplatesweb-component

Create and Use a Custom HTML Component?


I have the following local html:

<html>

<head>
  <link rel="import" href="https://mygithub.github.io/webcomponent/">
</head>

<body>
  <!-- This is the custom html component I attempted to create -->
  <img-slider></img-slider>
</body>

</html>

and the following attempt at a template:

<template>
  <style>
      .redColor{
        background-color:red;
      }
  </style>
  <div class = "redColor">The sky is blue</div>
</template>

<script>
  // Grab our template full of slider markup and styles
  var tmpl = document.querySelector('template');

  // Create a prototype for a new element that extends HTMLElement
  var ImgSliderProto = Object.create(HTMLElement.prototype);

  // Setup our Shadow DOM and clone the template
  ImgSliderProto.createdCallback = function() {
    var root = this.createShadowRoot();
    root.appendChild(document.importNode(tmpl.content, true));
  };

  // Register our new element
  var ImgSlider = document.registerElement('img-slider', {
    prototype: ImgSliderProto
  });
</script>

As described in this article. When I run the code, I get:

Uncaught TypeError: Cannot read property 'content' of null at HTMLElement.ImgSliderProto.createdCallback ((index):20)

In other words document.querySelector('template'); returns null. What gives?

My goal is to create custom html element and display it on the website that links the template code. I am 100% sure I am pulling the remote template code correctly (obviously, since I get the error in that code).

P.S. I am using latest Chrome, so I shouldn't need polyfills.


Solution

  • Try this:

      var tmpl = (document.currentScript||document._currentScript).ownerDocument.querySelector('template');
    

    The problem you ran into is that the template isn't really part of document but it is part of the currentScript. Due to polyfills and browser differences you need to check for currentScript and _currentScript to work correctly.

    Also be aware that HTML Imports will never be fully cross browser. Most web components are moving to JavaScript based code and will be loaded using ES6 module loading.

    There are things that help create templates in JS files. Using the backtick (`) is a reasonable way:

    var tmpl = document.createElement('template');
    tmpl.innerHTML = `<style>
      .redColor{
        background-color:red;
      }
    </style>
    <div class = "redColor">The sky is blue</div>`;