Last active
August 4, 2021 15:03
-
-
Save mattkenefick/6c5b8e540f77c3f112d0b7fc565b48f0 to your computer and use it in GitHub Desktop.
Shadow DOM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<main> | |
<my-paragraph> | |
Lorem ispum sit amet dolor | |
</my-paragraph> | |
<hr /> | |
<labeled-input> | |
This is the form label | |
</labeled-input> | |
</main> | |
<!-- Template for the MyParagraphElement class --> | |
<template id="my-paragraph"> | |
<style> | |
section { | |
background-color: #fde7fc; | |
padding: 5px; | |
} | |
</style> | |
<section> | |
<h3>Example Header</h3> | |
<div> | |
<slot>Ambulance is on its way</slot> | |
</div> | |
<button> | |
Click Me | |
</button> | |
</section> | |
</template> | |
<!-- Template for the LabeledInputElement class --> | |
<template id="labeled-input"> | |
<label> | |
<div><slot></slot></div> | |
<input type="text" /> | |
</label> | |
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Base class for our shadow elements | |
*/ | |
class CustomHtmlElement extends HTMLElement | |
{ | |
/** | |
* Optional template element. If one is not supplied, we | |
* will try to infer one based on the classname. | |
* | |
* @param HTMLElement template | |
* @return void | |
*/ | |
static attach(template) { | |
if (!template) { | |
// Convert MyParagraphElement to my-paragraph | |
const tagName = this.name | |
.replace(/([a-z0-9])([A-Z])/g, '$1-$2') | |
.toLowerCase() | |
.replace(/-?element/, ''); | |
template = document.querySelector(`#${tagName}`); | |
} | |
// Save template reference | |
this.template = template; | |
// Create shadow object | |
customElements.define(this.template.id, this); | |
} | |
/** | |
* @return void | |
*/ | |
constructor() { | |
super(); | |
// Clone element from our template | |
this.templateNode = this.constructor.template.content.cloneNode(true); | |
// Make shadow | |
this.attachShadow({ mode: 'open' }).appendChild(this.templateNode); | |
// Attach events call | |
this.attachEvents(); | |
} | |
/** | |
* @return void | |
*/ | |
attachEvents() { | |
// Not implemented | |
} | |
/** | |
* @return void | |
*/ | |
detachEvents() { | |
// Not implemented | |
} | |
} | |
/** | |
* Custom element class extends our root class | |
* | |
* @extends CustomHtmlElement | |
*/ | |
class MyParagraphElement extends CustomHtmlElement { | |
/** | |
* Attach events to the DOM | |
* | |
* @return void | |
*/ | |
attachEvents() { | |
this.shadowRoot | |
.querySelector('button') | |
.addEventListener('click', this.Handle_OnClickButton); | |
} | |
/** | |
* Respond to click events | |
* | |
* @param MouseEvent e | |
* @return void | |
*/ | |
Handle_OnClickButton(e) { | |
alert('This button has been clicked'); | |
} | |
} | |
/** | |
* Basic labeled input | |
* | |
* @extends CustomHtmlElement | |
*/ | |
class LabeledInputElement extends CustomHtmlElement { | |
// Not implemented | |
} | |
// ------------------------------------------------------------------------- | |
// ⬇︎ We could explicitly pass in an element | |
// const element = document.querySelector('#my-paragraph'); | |
// MyParagraphElement.attach(element); | |
// ⬇︎ Or we could derive it from the class name automatically | |
// MyParagraphElement.attach(); | |
// ⬇︎ Or we can try to infer it inversely based on our templates | |
Array.from(document.getElementsByTagName('template')).forEach(element => { | |
// Convert "my-paragraph" to "MyParagraphElement" | |
const className = element.id | |
.replace(/^([a-z])/, m => m.toUpperCase()) | |
.replace(/-([a-z])/g, m => m.toUpperCase()) | |
.replace('-', '') | |
+ 'Element'; | |
const reference = eval(className); | |
reference.attach(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment