Web Component Starter Template
This is my base line starter template for a web component. Note that it's my first attempt at this so there's probably thing that could be imporved in terms of effifiency, but it's all working as expected
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