load-file Web Component

by WebComponents

HTML

<style>
  body> img,
  load-file,
  svg {
    --height: var(--fullheight,150px); /* CSS properties cascade into shadowDOM!! */
    height: var(--height);
  }
  path:nth-child(2n+1) {
    fill: RED; /* global Style does NOT style shadowDOM */
  }
</style>
<h4>&lt;img src=".../heart.svg"></h4>
<img src="//load-file.github.io/heart.svg">

<h4>Load in main DOM: &ltload-file  replaceWith  src=".../heart.svg"></h4>
<load-file replaceWith src="//load-file.github.io/heart.svg"></load-file>

<h4>Load in shadowDOM: &ltload-file src=".../heart.svg"></h4>
<load-file src="//load-file.github.io/heart.svg">
  <!-- elements marked shadowRoot inside load-file are MOVED to shadowDOM -->
  <style shadowRoot>
    svg {
      height: var(--height); /* CSS Properties cascade into shadowDOM!! */
    }
    path:nth-child(2n+2) {
      fill: GREEN; /* shadowDOM style does NOT style global DOM */
    }
  </style>
</load-file>

CSS

/* styling for use in Dev.to post */
body {
  font: 16px arial;
  background: khaki;
  --xxxfullheight:200px;
}
h4 {
  margin: 0 auto;
  xxxdisplay:none;
}

xxxfile-size::before{
  margin-bottom:1em;
  display:block;
  text-align:center;
  font-size:180%;
  content:'<load-file [replaceWith] src=".../heart.svg">';
}

JavaScript

/*
  defining the <load-file> Web Component,
  yes! the documenation is longer than the code
  License: https://unlicense.org/
*/
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 
    src = this.getAttribute("src"),
    // attach a shadowRoot if none exists (prevents displaying error when moving Nodes)
    // declare as parameter to save 4 Bytes: 'let '
    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 <load-svg> innerHTML/lightDOM after parsed <svg>
    shadowRoot.append(...this.querySelectorAll("[shadowRoot]"))

    // if "replaceWith" attribute exists
    // then replace <load-svg> with loaded content <load-svg>
    // childNodes instead of children to include #textNodes also
    // spelled replaceWith for optimal GZip compression, and matches the actual JS code
    this.hasAttribute("replaceWith") && this.replaceWith(...shadowRoot.childNodes)
  }
})