Mike Schreiber



Img Fallback

Component

Img Fallback is a component that wraps an img element. It takes a src attribute. If the wrapped image fails to load, the component will attempt to have the img fallback to the image specified in src.

Img Fallback uses display: contents in order to not act as a block around the image it wraps. This allows the component to act as a pure decorator for the img within, so users can continue to develop with the img as they normally would.

class ImgFallback extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); this.shadowRoot.appendChild(ImgFallback.template.content.cloneNode(true)); } connectedCallback() { this.querySelectorAll('img').forEach((img) => { if (img.complete) { if (img.naturalWidth === 0) { this.#loadFallback(img); } } else { img.addEventListener('error', (event) => this.#loadFallback(event.target)); } }) } #loadFallback(img) { const fallbackSrc = this.getAttribute('src'); if (!fallbackSrc) return; if (img.src === fallbackSrc) return; img.src = fallbackSrc; } } ImgFallback.template = document.createElement('template') ImgFallback.template.innerHTML = ` <style> :host { display: contents; } </style> <slot></slot> `; window.customElements.define('img-fallback', ImgFallback);

Demo

<img-fallback src="https://via.placeholder.com/200x200?text=fallback"> <img src="https://via.placeholder.com/200x200?text=main"> </img-fallback> <img-fallback src="https://via.placeholder.com/200x200?text=fallback"> <img src="/none1.jpg"> </img-fallback> <img-fallback src="https://via.placeholder.com/200x200?text=lazy+fallback"> <img src="https://via.placeholder.com/200x200?text=lazy+main" loading="lazy"> </img-fallback> <img-fallback src="https://via.placeholder.com/200x200?text=lazy+fallback"> <img src="/none2.jpg" loading="lazy"> </img-fallback>