1

Consider this simple page:

<html>
<body>
   <svg width="250" height="250">
      <g>
         <path id="foo" d="M20,230 Q40,205 50,230 T90,230" stroke="red" stroke-width="3" fill="none" onclick="setBlue()" />
      </g>
   </svg>
   <script>
      function setBlue() {
         document.getElementById("foo").setAttribute("stroke", "blue");
      }
   </script>
</body>
</html>

It will display a red squiggly line. If you click on the line, it will turn blue. This demonstrates that JavaScript functionality is working inside this SVG object and also that the path element foo was added to the DOM itself.

Now instead load a static SVG that a browser could cache:

<img width="250" height="250" src="images/somesvg.svg" />

The embedded JavaScript does not hit. Asking the DOM for foo via JavaScript or jQuery returns nothing.

Does this mean the only way to name elements inside the SVG or to add JavaScript functionality is via rendering the SVG inside the HTML itself? I could shorten a page up significantly if I could add IDs to paths in an SVG file and then access them.

Paul
  • 5,700
  • 5
  • 43
  • 67
  • 1
    "Does this mean the only way to name elements inside the SVG or to add JavaScript functionality is via rendering the SVG inside the HTML itself?" - Yeah, svgs rendered with an img tag will be treated statically like a raster image . If you cant keep them inline in the file, the best method imo is to use javascript to fetch and inject them as inline svgs, but see discussion here for alternatives to that and https://stackoverflow.com/questions/4476526/do-i-use-img-object-or-embed-for-svg-files , particularly the parts about the and tags. – diopside Nov 01 '21 at 18:23
  • is [this](https://stackoverflow.com/questions/4476526/do-i-use-img-object-or-embed-for-svg-files) what you're looking for? – Robert Longson Nov 01 '21 at 19:29
  • You can add any element from external svg by ``. And that might be a whole svg inside svg in DOM. – Leonid Nov 01 '21 at 20:16

2 Answers2

4

If it is an external *.svg file, A native Web Component <load-file> can fetch it and inject it in the DOM; either in shadowDOM or replacing the <load-file> Element, thus becoming part of the DOM you can access and style with CSS.

customElements.define("load-file", class extends HTMLElement {

  // declare default connectedCallback as async so await can be used
  async connectedCallback(
    // call connectedCallback with parameter to *replace* SVG (of <load-file> persists)
    src = this.getAttribute("src"),
    // attach a shadowRoot if none exists (prevents displaying error when moving Nodes)
    shadowRoot = this.shadowRoot || this.attachShadow({mode:"open"})
  ) {
      // load SVG file from src="" async, parse to text, add to shadowRoot.innerHTML
    shadowRoot.innerHTML = await (await fetch(src)).text()

    // append optional <tag [shadowRoot]> Elements from inside <load-svg> after parsed <svg>
    shadowRoot.append(...this.querySelectorAll("[shadowRoot]"))

    // if "replaceWith" attribute 
    // then replace <load-svg> with loaded content <load-svg>
    // childNodes instead of children to include #textNodes also
    this.hasAttribute("replaceWith") && this.replaceWith(...shadowRoot.childNodes)
  }
})

Full explanation in Dev.To post: 〈load-file〉Web Component, add external content to the DOM

Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
3

As @diopside and @RobertLongson mention in the comments, the question was asked a different way here: Do I use <img>, <object>, or <embed> for SVG files?

The solution was to use <object> and embed the SVG in that. Now I can interact with it yet the browser doesn't need to reload the image each time the page loads.

Paul
  • 5,700
  • 5
  • 43
  • 67