How to show different fallback content with Web Components
Thu Apr 23 2020
With web components there's often a need to render fallback content - both to show content in browsers that don't have support for web components (or with JavaScript disabled/broken) and to show content to the user while the web component is being loaded/initialised. The trouble is that we probably want to display different fallback content in these two scenarios - perhaps alternative static content in the first case and a loading indicator in the latter.
Fallback content is provided by supplying HTML between our custom element tags, but how do we have 2 different version of fallback content?
To achieve this we first build our component as normal:
class WCExample extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
}
render() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
padding: 1rem;
color: steelblue;
border: 1px solid steelblue;
}
</style>
<p>Loaded and ready to go!</p>
`;
}
}
customElements.define('wc-example', WCExample);
Next we provide our two versions of fallback content inside out new element, providing different classes to each:
<wc-example>
<p class="no-wc">A static version of the content</p>
<p class="has-wc">Please wait...</p>
</wc-example>
If we were to load this HTML in the browser we'd see both versions of the fallback content until the component code is loaded. However if we apply a class to the body
indicating no web component support, .no-wc
, and immediately remove it just after the body
tag if web components are supported (before the component code is loaded or the component tag is rendered):
if (window.customElements) {
document.querySelector('body').classList.remove('no-wc');
}
The body will then only have the .no-wc
class if JavaScript has run and Web Components are supported. We can then control which version is displayed with a couple of global CSS rules:
body.no-wc .has-wc {
display: none;
}
body:not(.no-wc) .no-wc {
display: none;
}
See this in action here (with an artifical delay applied to the loading of the Web Component code). Be sure to test with and without JavaScipt enabled to see the difference.