Search code examples
javascriptxmlsvgfirefox

Firefox: shadow-DOM compatibility


I have some JavaScript that works fine on current versions of Chrome but doesn't work with Firefox. Event triggers for hover and click fail with Firefox, which I believe is a shadow DOM issue.

I can substitute the JavaScript hover code for CSS, which does work with Firefox (doesn't with Chrome) but this will not solve the issue for click events.

How can cross browser compatibility be achieved here?

let elementsArray = document.querySelectorAll(".icon");
elementsArray.forEach(function(elem) {
    console.log("getting element -"+String(elem));
    elem.addEventListener("mouseenter", function() {
      elem.setAttribute("style", " filter: grayscale(100%);");
    });
    elem.addEventListener("mouseout", function() {
      elem.setAttribute("style", "");
    });
    elem.addEventListener("click", function() {
      let hex = this.getAttribute('id');
      console.log(hex);
    });
});
 <svg 
   width="600"
   height="100" 
   >

<g id="layer0" class="slide" >
<path class="icon" id="y2011_0" d="M 285.0,45.0 300.0,70.98076211353316 285.0,96.96152422706632 255.0,96.96152422706632 240.0,70.98076211353316 255.0,45.0 z" fill="rgba(124,38,10,0.500000)"/>
<path class="icon" id="y2011_1" d="M 330.0,19.019237886466843 345.0,45.0 330.0,70.98076211353316 300.0,70.98076211353316 285.0,45.0 300.0,19.019237886466843 z" fill="rgba(124,39,10,0.500000)"/>
</g>
<use id="use" xlink:href="#layer0" href="#layer0" />
</svg>


Solution

  • A lot less code and more control if you create the SVG dynamically
    with a W3C standard Web Component (JSWC supported in all modern Browsers)

    <style>
      svg  { background: pink }
      path { stroke: blue }
    </style>
    <game-board>
      <hexagon x="46"  y="0"  />
      <hexagon x="138" y="0"  />
      <hexagon x="92"  y="26" />
      <hexagon x="138" y="52" />
      <hexagon x="92"  y="78" />
      <hexagon x="184" y="26" />
    </game-board>
    <script>
      customElements.define("game-board", class extends HTMLElement {
        connectedCallback() {
          setTimeout(() => {
            let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
            svg.innerHTML = `<style>` +
              `.hexagon{fill:red}.hexagon:hover{filter:grayscale(100%);cursor:pointer}` +
              `.hexclicked{fill:green}` +
              `</style>`;
            svg.append(...[...this.querySelectorAll("hexagon")].map(hex => {
              let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
              path.setAttribute("d", `m${hex.attributes.x.value} ${hex.attributes.y.value} 15 26-15 26-30 0-15-26 15-26z`);
              path.classList.add("hexagon");
              path.onclick = (evt) => path.classList.toggle("hexclicked");
              return path;
            }));
            this.replaceWith(svg);
          })
        }
      })
    </script>

    <hexagon> is an UnknownElement; save to use,
    see: https://dev.to/dannyengelman/web-components-using-unknownhtmlelements-for-better-semantic-html-5d8c