Search code examples
javascriptcsshtmlweb-componentshadow-dom

shadow dom script to watch for changes in host


I am creating an app where I need to manage a collection of elements that take advantage of the shadow dom. Since the template tag encapsulates content, I can keep the style and script with the elements in order for them to act on events. What I would like to know is if it is possible for script inside the shadowRoot to observe changes to properties of the host.

My proposed path is to attach a data attribute to the host and have shadow script listen for changes to it and then update elements inside the shadowRoot. I am aware that it is possible to use javascript to access elements in the shadowRoot and change them, but my desire is to experiment in modularization and reusability. I ultimately would like for this component to be reusable and react to changes in the hosts attributes.


Solution

  • I found a solution and figured I would share. It is likely not yet compatible with all browsers, but such is life.

    In my script, I have a iffe/monad that processes my custom html tags, creating shadow roots and clones of a template as content. One of the arguments for the monad is the array of nodes that match my custom tag. While looping over them, I create a MutationObserver to watch for a particular attribute change in order to use the created shadow root in a closure.

                (function (tags, template) {
                Array.prototype.forEach.call(hexagons, function (v, k) {
                        var shadow = v.createShadowRoot();
                        shadow.appendChild(template.content.cloneNode(true));
    
                        /* mutation observer */
                        var observer = new MutationObserver(function (mutations) {
                                mutations.forEach(function (mutation) {
                                    shadow.querySelector('.seconds')
                                       .innerText(
                                          mutation.target.getAttribute(mutation.attributeName)
                                       )
                                });
                            });
                        observer.observe(v, { attributes: true, attributeFilter: ['bgcolor'] });
                    }
                );
            }(document.querySelectorAll('time'), document.querySelector('template#time')));
    

    The above works in Chrome and Firefox latest. I will keep looking for mroe browser friendly solutions.