Search code examples
jqueryinternet-explorer-11web-componentshadow-domangular-elements

Using jQuery in Internet Explorer to Pierce Shadow DOM


I am trying to use jQuery inside an Angular Elements web component with ShadowDom encapsulation and running into problems with internet explorer, specifically IE11. An error is triggered when resolving to the shadowRoot and then using the jQuery find method with a selector other than an ID. The error message is:

Unable to get property 'length' of undefined or null reference

I created a simple page to isolate the problem and was able to reproduce the same error.

    <h2>Hello from outside the Shadow DOM!</h2>

    <div class='parent'></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/shadydom/1.1.0/shadydom.min.js"></script>
    <script
      src="https://code.jquery.com/jquery-3.4.1.js"
      integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
      crossorigin="anonymous"></script>

    <script>
      // Setup an element in the shadow DOM
      var element = $('.parent')[0];
      var shadow = element.attachShadow({mode: 'open'});

      var text = document.createElement('span');
      text.id = 'subtitle';
      text.textContent = 'Hello from inside the Shadow DOM!';

      shadow.appendChild(text);      
      //-- End Setup

      // This is how the web component code is getting access to the shadow root
      var shadowRoot = $(element.shadowRoot);

      // No problems with this find call
      var subtitle = shadowRoot.find('#subtitle');

      // IE Bug is triggered here
      var span = shadowRoot.find('span');

      console.log('jQuery set count: ' + span.length);
    </script>

And here is the stack when the error occurs:

Error Stack Trace

Is this a known issue with jQuery and piercing the shadow DOM in IE11? Are there any solutions?


Solution

  • I found a workaround that works consistently on IE11 and Chrome. Putting the shadow DOM elements within a container div that has an ID allows for resolving to the container and finding the elements from that context. Here is the updated code:

    <script>
      // Setup an element in the shadow dom
      var element = $('.parent')[0];
      var shadow = element.attachShadow({mode: 'open'});
    
      var container = document.createElement('div');
      container.id = 'container';
      container.innerHTML = '<span>Hello from inside the Shadow DOM!</span>'
    
      shadow.appendChild(container);      
      //-- End Setup
    
      // This is how site search get access to the shadow root
      var shadowRoot = $(element.shadowRoot);
    
      // Use the shadow root to resolve to the cotnainer by ID 
      // and then finding any other elements in the shadow DOM
      // works as expected.
      var container = shadowRoot.find('#container');
      var span = container.find('span');
    
      console.log('jQuery set count: ' + span.length);
    
    </script>