<!-- This first example has its content defined in JavaScript -->
<js-description header="Web Components 101">I have been working on figuring out <a href="https://www.webcomponents.org/">web components</a>. This explanitory text is an example of the kind of thing that you can do. Below is another example of what you can do.</js-description>

<!-- This second example has it's content defined in a template -->
<template id="gravatarTemplate">
<js-gravatar email="joe@jws.app"></js-gravatar>
// ** For the intro example **
// Create MyComponent
class MyComponent extends HTMLElement {
  connectedCallback() {
    // What content goes into MyComponent?
    this.innerHTML = `<h1>`+this.getAttribute("header")+`</h1><p>`+this.innerHTML+`</p>`;
// Attach MyComponent to js-description
customElements.define('js-description', MyComponent);

// ** For the gravitar example **
// Gravatar needs an MD5 hash of the email, so we are using a 3rd party library for that
function updateImg(img, email) {
    img.setAttribute("src", "//www.gravatar.com/avatar/" + SparkMD5.hash(email));

var gravatarElementPrototype = Object.create(HTMLElement.prototype);
gravatarElementPrototype.attributeChangedCallback = function (attributeName, oldVal, newVal) {
    if (attributeName == "email") {
			// this.shadowRoot is the root node of a DOM subtree that is rendered separately from a document's main DOM tree        
			updateImg(this.shadowRoot.querySelector('img'), newVal);
gravatarElementPrototype.createdCallback = function () {
    var t = document.querySelector('#gravatarTemplate');
    var clone = document.importNode(t.content, true);
    updateImg(clone.querySelector('img'), this.getAttribute("email") || "");

var MyGravatarElement = document.registerElement('js-gravatar', {
    prototype: gravatarElementPrototype

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.0/spark-md5.min.js