Web Component Starter Template
This is my base line starter template for a web component
The Component JavaScript
customElements.define('wc-starter',
class extends HTMLElement {
static get observedAttributes() {
return ['data-externaltointernal']
}
constructor() {
super()
this.attachShadow({mode: 'open'})
const tempHolder = document.createElement("div")
const tempString = `
<template id="starterComponent">
<p>From attribute: <span id="initialAttr">-</span></p>
<p class="wcHighlight">Highlighted from external style sheet set via attribute</p>
<p>From slot on page: <slot name="slotContent"></slot></p>
<label for="ctrl">Internal component ranger input:<label>
<input type="range" id="ctrl" name="ctrl" />
<p>From internal component range input: <span id="output"></span></p>
<p>From external range input: <span id="externaltointernaloutput"></span></p>
</template>`
tempHolder.innerHTML = tempString
const el = tempHolder.childNodes[1].content.cloneNode(true)
const controller = el.getElementById("ctrl")
const output = el.getElementById("output")
controller.addEventListener("input", (event) => {
output.innerHTML = event.target.value
this.dataset.sendit = event.target.value
})
this.shadowRoot.append(el)
}
getStyleSheet() {
if (this.dataset.stylesheet !== undefined) {
const styles = document.createElement('link')
styles.setAttribute('rel', 'stylesheet')
styles.setAttribute('href', this.dataset.stylesheet)
this.shadowRoot.append(styles)
}
}
loadAttribute() {
const initialAttr = this.hasAttribute('initialAttr')
? this.getAttribute('initialAttr')
: "No initialAttr Found"
this.shadowRoot.getElementById("initialAttr").innerHTML = initialAttr
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === "data-externaltointernal" && newValue !== oldValue) {
this.shadowRoot.getElementById("externaltointernaloutput").innerHTML = newValue
}
}
connectedCallback() {
this.getStyleSheet()
this.loadAttribute()
}
}
)
HTML
<wc-starter
id="wcExample"
initialAttr="Sierra"
data-stylesheet="/styles/example-alfa.css"
data-sendit="0"
data-externaltointernal="0">
<span slot="slotContent">Tango</span>
</wc-starter>
<div>
<label for="externalInput">Send external input<label>
<input type="range" id="externalInput" name="externalInput" />
</div>
<div>External view of component range: <span id="fromComponent"></span></div>
The HTML
External view of component range:
The Page JavaScript
const handleInsideMutations = (mutationList, observer) => {
for (const mutation of mutationList) {
if (mutation.attributeName === 'data-sendit') {
const oldValue = mutation.oldValue
const newValue = mutation.target.attributes.getNamedItem(
mutation.attributeName
).value
if (newValue !== oldValue) {
fromComponent.innerHTML = newValue
}
}
}
}
const handleExternalInput = (event) => {
const newValue = event.target.value
document.getElementById('wcExample').dataset.externaltointernal = newValue
}
const init = () => {
document
.getElementById('externalInput')
.addEventListener('input', handleExternalInput)
const theComponent = document.getElementById('wcExample')
const observer = new MutationObserver(handleInsideMutations)
observer.observe(theComponent, { attributes: true })
}
document.addEventListener('DOMContentLoaded', init)
Features
-
Single call (doesn't define class before adding it)
-
Includes template directly inside JavaScript
-
Call an external stylesheet
-
Get content from a slot
-
Get data from a attribute set in parent element call
-
Get feedback inside the component from a form inside the component
-
Get feedback outside the component from a form inside the component
-
Get feedback inside the component from a form outside the component