DEV Community

Cover image for 〈load-file〉Web Component, add external content to the DOM
Danny Engelman
Danny Engelman

Posted on • Updated on

〈load-file〉Web Component, add external content to the DOM

Whilst we are waiting for HTML Modules to arrive in all Browsers (Chrome Platform Status)

The〈load-file〉Web Component

✔️ Fetches any external text file: ie. .txt , .svg , .html

✔️ Injects the content into the DOM

  • in shadowDOM

    • respects lightDOM content for shadowDOM <slot> elements
    • with optional scoped CSS styling! ✨✨✨
    • can move lightDOM content to shadowDOM
  • Or replaces the <load-file> element itself with the replaceWith attribute

✔️ is not a replacement for 'HTML Imports'; <script> will not execute

✔️ is done in 7 lines of code:


There are multiple ways to put an external SVG file on the page

source: https://vecta.io/blog/best-way-to-embed-svg

   <load-file replaceWith src="//load-file.github.io/heart.svg"></load-file>

   <load-file src="//load-file.github.io/heart.svg">
    <style shadowRoot>
      path:nth-child(2n+2) {
        fill: GREEN; /* shadowDOM style does NOT style global DOM */
      }
    </style>
   </load-file>
Enter fullscreen mode Exit fullscreen mode
  • display as bare SVG, by using the replaceWith attribute
    • (global) CSS styles all SVGs (see red heart puzzle pieces)
  • OR, display contained in shadowDOM
    • now (local) CSS styles one SVG (see green heart puzzle pieces)


Loading the <load-file> Web Component

Load the element from the Repo

<script src="https://load-file.github.io/element.js"></script>
Enter fullscreen mode Exit fullscreen mode

It doesn't matter when the Custom Element is loaded/defined.

Any existing <load-file> elements in the document will automagically upgrade when the Custom Element is defined later.

or define the entire element in the <head> of your HTML document with a <script> tag:

<script>
customElements.define("load-file",class extends HTMLElement{async connectedCallback(){
this.shadowRoot||this.attachShadow({mode:"open"});this.shadowRoot.innerHTML=await(
await fetch(this.getAttribute("src"))).text();this.shadowRoot.append(...this.children);
this.hasAttribute("replaceWith")&&this.replaceWith(...this.shadowRoot.children)}})
</script>
Enter fullscreen mode Exit fullscreen mode

Using the <load-file> Web Component

Specify the full path in the src attribute

add the replaceWith attribute so the src content replaces the <load-file> Element itself in the document

<load-file  replaceWith  src="https://load-file.github.io/heart.svg"></load-file>
Enter fullscreen mode Exit fullscreen mode

!! Note the CAPITAL in replaceWith (creates a better GZip compressed file)

Without replaceWith the source content will be injected in shadowDOM:

<load-file src="https://load-file.github.io/heart.svg"></load-file>
Enter fullscreen mode Exit fullscreen mode

All elements with attribute shadowRoot are moved to shadowDOM:

<load-file src="https://load-file.github.io/heart.svg">
    <style shadowRoot>
      path:nth-child(2n+2) {
        fill: GREEN; /* shadowDOM style will NOT style global DOM */
      }
    </style>
</load-file>
Enter fullscreen mode Exit fullscreen mode





Top comments (2)

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

Pretty cool, I like it :D

However, you forgot to mention SVG can be loaded with <object>, which allows some more of the CSS inside the SVG to do its magic, outside style rules still don't apply, but if I remember correctly, outside custom properties are available inside the SVG.

Collapse
 
dannyengelman profile image
Danny Engelman • Edited

Tnx,

I added object and a link to vecta.io/blog/best-way-to-embed-svg which describes all in detail

Also changed functionality slightly. Only the first <style> element will now be moved to shadowDOM. That way any <slot> element in a loaded .html file will slot content from lightDOM correctly