shadow root and custom elements

by Laurens Maneschijn

HTML

<hello-world>
	Old content not visible
	<small>(but could be used as fallback content)</small>
</hello-world>
<hr>

<hello-shadow>
	Old content not visible
	<small>(but could be used as fallback content)</small>
</hello-shadow>

<hr>
N.B. : <code>&lt;a-a&gt;</code> will not work, need to use <code>&lt;a is="a-a"&gt;</code> for extended children of HTMLElement.<br>

<a-a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/customElements">a-a</a-a> <br>
<a is="a-a" href="https://developer.mozilla.org/en-US/docs/Web/API/Window/customElements">a is="a-a"</a> <br>

<hr>
<popup-handle></popup-handle>

<popup-handle>simple <b>popup</b> html content</popup-handle>

<hr>

<popup-handle>
	<handle>
		<button>custom <i>handle</i></button>
	</handle>
	<popup>
		<b>popup</b> content html<br>
		multiline
		<popup-handle>
			nested popup
			<popup-handle>another nested popup</popup-handle>
		</popup-handle>
	</popup>
</popup-handle>



<hr>

<div style="position:fixed; top:0; right:0; background: #eeee; margin:5px; padding:5px;">
	links:<br>
	<a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/customElements">customElements</a><br>
	<a href="https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define">CustomElementRegistry.define()</a><br>
	<a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM">Using_shadow_DOM</a><br>
	
</div>

JavaScript

// https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#parameters :
// "Note that custom element names must contain a hyphen."

// <hello-world> : custom element with static content
customElements.define('hello-world',
  class extends HTMLElement {
    constructor() {
      super();
	  console.log(this);

	  // This replaces old content with new static content:
	  this.textContent = 'hello-world';
    }
  }
);

// <hello-shadow> : custom element replacing element with custom content using shadow DOM.
customElements.define('hello-shadow',
  class extends HTMLElement {
    constructor() {
      super();
	  console.log(this);

	  // NB: as soon as attachShadow() is called, all existing inner html content is ignored and not visible.
      const shadowRoot = this.attachShadow({mode: 'open'});
	  const style = document.createElement('style');
      const span = document.createElement('span');
	  shadowRoot.appendChild(style);
	  shadowRoot.appendChild(span);
	  style.textContent = 'span { display: inline-block; background: #8884; border: 1px solid #888; border-radius: 4px; margin: 2px; padding: 2px; }';
	  span.textContent = 'hello-shadow';
    }
  }
);


// Extend existing element example:
// <a is="a-a"> : custom element; as <a> but copies href attribute value to textContent:
// i.e. <a is="a-a" href="xxx"></a> will act as: <a href="xxx">xxx</a>
customElements.define('a-a',
	class extends HTMLAnchorElement {
		constructor() {
			super();
			console.log(this);
			this.textContent = this.getAttribute('href');
			this.setAttribute('title', this.getAttribute('href'));
			// It seems we can safely remove the is="xxx" attribute now so it looks cleaner in inspected elements:
			this.removeAttribute('is');
		}
	},
	{extends: 'a'}
);

// Based on example from:
// https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM
// https://mdn.github.io/web-components-examples/popup-info-box-web-component/

class PopUpHandle extends...