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
- respects lightDOM content for shadowDOM
Or replaces the
<load-file>
element itself with thereplaceWith
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
-
👉 as src :
<img src="file.svg">
- SVG content can not be styled with CSS
-
👉 as Object :
<object type = "image/svg+xml" data="file.svg"></object>
- CORS restrictions apply
-
👉 as CSS background-image
background-image: url(file.svg)
-
👉 🎉 use the
<load-file>
Web Component 🎉- it provides scoped CSS styling
- Load the 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>
- 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>
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>
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>
!! 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>
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>
Top comments (3)
Thanks for the list. I've learned two cool new ways to add external content to the DOM. However, I'm not convinced on using the object tag for loading an svg. Rarely does one use SVG on a web page without having to adjust the styling. But you can't selectively style the svg inside the external object tag. And if you have to change the styles inside the SVG itself, that makes the SVG file less versatile.
In the end, I used CSS mask with the
mask-image
property pointing to the SVG.However, for embedding content that you don't intend to change, like a pdf, or video, the object tag is a great method.
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.Tnx,
I added
object
and a link to vecta.io/blog/best-way-to-embed-svg which describes all in detailAlso 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