Shawn Volpe
Shawn Volpe

Reputation: 407

Is it possible to bind an event listener to an element within a shadow dom from external script?

I have a chrome extension that injects a shadow dom element to a page to keep the css separate. But I need to bind an onclick to some elements within the shadow dom from a content script because I need to be able to invoke functions in the content script by clicking on the elements that are in the shadow dom.

I have tried using the .bind('click', function(){}) on both the elements in the template element and the actual shadow dom element but I can't seem to access them. Is this possible?

Upvotes: 21

Views: 15423

Answers (3)

Anas
Anas

Reputation: 742

I'm using alternative way with Jquery find and on function, try my snippet here.

$("#CreateShadowRoot").on('click', function (event) {
    const shadowDiv = document.getElementById('ShadowDiv');
    const shadowRoot = shadowDiv.attachShadow({ mode: 'open' });
    const jQueryScript = document.createElement('script');
    jQueryScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'; 
    shadowRoot.appendChild(jQueryScript);
    shadowRoot.innerHTML += '<button id="example-action">Im inside ShadowRoot</button>';
    function initShadowDOM() {
      // Get the Shadow DOM root element
      // Attach a click event listener using jQuery
      $(shadowRoot).find("#example-action").on('click', function (event) {
        // Handle the click event within the Shadow DOM
        // You can access the event object and perform actions here
        console.log('Event received');
      });
    }
    jQueryScript.onload = function () {
      // jQuery is now loaded and ready to use
      // You can use jQuery event listeners like .on() here
      initShadowDOM(); // Call a function to set up the Shadow DOM content and event listeners
    };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="CreateShadowRoot">Create ShadowRoot</button>
<div id="ShadowDiv"></div>

Upvotes: 0

Abhinav
Abhinav

Reputation: 1366

I have tried using the .bind('click', function(){}) on both the elements in the template element

  1. Adding event listener to template won't work. The element you are binding to should be part of DOM.

and the actual shadow dom element but I can't seem to access them

  1. I don't think jquery understands shadow-root yet. If you are using jquery to query for elements in shadow-dom I don't think it will return a node(Should it?)

So, you have 2 options:

  1. As suggested in other answer, you can bind eventlistener to actual element by querying for it inside shadow-root, which can by accessed by shadowRoot property on element.
  2. Or, you can use jquery event-delegation to bind event listener on parent(in this case host of shadow-dom) with appropriate selector. When event will be propagated to parent, listener will be fired.

Ex:

$( "#list" ).on( "click", "a", function( event ) {
    event.preventDefault();
    console.log( $( this ).text() );
});

Upvotes: 0

Dogs
Dogs

Reputation: 3167

Try querying against the element's shadowRoot. In other words, lets say you have an element <super-ultra-element>, and inside that element's shadow dom is a div with class 'potato' that you wish to attach a click handler to.

You should be able to do this by first obtaining the element's shadowRoot: var superUltraRoot = document.querySelector('super-ultra-element').shadowRoot;.

Once you have the shadowRoot, you can query the element's shadow dom for the item you care about: var potatoDiv = superUltraRoot.querySelector('.potato');.

You now have a reference to the element you're trying to add a click handler to, so doing so should be fairly easy: potatoDiv.addEventListener('click', someClickCallback);

Upvotes: 29

Related Questions