Search code examples
javascriptweb-componentshadow-domcustom-element

How to add JavaScript to Custom Elements?


I have the following code, which creates a custom element, encapsulated with Shadow DOM:

'use strict'
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {

    var root = this.createShadowRoot();
    var divEl = document.createElement('div');
    divEl.setAttribute("id", "container");
    divEl.innerHTML =
        "<input id='input' type='text'>"
      + "<br>"
      + "Result: <span id='result'></span>"
      + "<br><button onclick='performTask()'>Run</button>";
    root.appendChild(divEl);

};
document.registerElement('custom-ele', {
    prototype: proto
});

The idea is, when 'Run' is clicked, the input would be taken from the input element and processed (in performTask()), then the output placed into '#result'. My two questions are:

  1. How would I grab the value from the input field in the Shadow DOM?
  2. How would I place the output into #result?

This previous stack overflow post looks like it would have answered my question, but all the suggested links are no longer valid so am wondering if anyone could point me in the right direction :)

P.S. I'd rather not use templates since HTML Imports are not being supported by all browsers and I want all of my custom element code contained in one file.


Solution

  • Turns out you can add functions to the shadow root itself, then you can just call this.parentNode.fn() on the shadow roots direct children to access the shadowRoot...

    proto.createdCallback = function() {
    
        let root = this.createShadowRoot();
    
        root.innerHTML = "<input id='input' type='text'>"
            + "<br>"
            + "Result: <span id='result'></span>"
            + "<br><button onclick='this.parentNode.process()'>Run</button>";
    
        this.shadowRoot.process = function() {
            let spanEle = this.querySelector('span');
            let inputEle = this.querySelector('input');
            spanEle.textContent = performAlgorithm(inputEle.value.split(','));
        };
    };
    document.registerElement('custom-ele', { prototype: proto });
    

    (Thanks to MarcG for giving me the initial insight)