home ~ projects ~ socials

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

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()
    }

  }
)
Tango
External view of component range:

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

TODO

    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

-- end of line --