HTML Web Components
When evaluating web components for the blog, I also came around a different idea. Can we build web components that don't want to use shadow DOM? Would it make sense to do so?
Another element to look at is to build web components for some aspects of the blog using either bare bones web components that eschew the shadow DOM, or libraries like Lit, Wired Elements or Shoelace/Web Awesome.
The basic idea is this:
- Create a web component
- Insert the content in the component's light DOM
- Evaluate if styling is appropriate or not
Hand Written Web Components #
Most of the time when I see web components in a page, I see this:
<my-component></my-component>
Until this component initializes with the connectedCallback
lifecycle callback there is not content displayed on the page. If the component is not initialized then nothing will display on the page.
Likewise, if we use shadow DOM or templates and the page is not initialized or the Javascript fails to load then there will be no content displayed on the page.
But what happens if we just load HTML inside the web component? Do we still need to initialize it via Javascript?
Asking the question Jeremy Keith has asked in his presentations about technology How well do web components fail?
Using the super-slider
component from Eric Meyer's post, let's look at the element itself. Instead of leaving it bare we insert the children directly into the HTML, in the light DOM if you want, and use web component lifecycle methods to wire the necessary scripting.
The HTML looks similar to what we'd do instead of using a web component. We just wrap a web component
<super-slider unit="em" target=".preview h1">
<label for="title-size">Title font size</label>
<input id="title-size" type="range" min="0.5" max="4" step="0.1" value="2" />
</super-slider>
We define the custom element in Javascript using a class that extends the HTML element.
The constructor is optional, but I always use it to ensure proper inheritance from the parent.
In the connectedCallback
we initialize the component and its children.
finally we match the Javascript with the custom element name using the define
method of the CustomElementRegistry interface.
class superSlider extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
let targetEl = document.querySelector(this.getAttribute('target'));
let unit = this.getAttribute('unit');
let slider = this.querySelector('input[type="range"]');
slider.addEventListener("input",(e) => {
targetEl.style.setProperty('font-size', slider.value + unit);
});
}
}
customElements.define("super-slider",superSlider);
SO what's the difference between an element define like this and a traditional custom element?
It makes the page easier to understand, it provides a fallback in case the script fails to load and it provides a way to enhance the content without adding bloat to the page.
Whether you use this style of components or choose to use shadow DOM to hide content and styles inside the component, or even choose to skip web components altogether, is your choice based on what your project needs.
Links and Resources #
- Blinded by the Light DOM — Eric Meyer
- HTML Web Components — Jeremy Keith
- Shadow DOM is not a good default — Robin Rendle
- HTML Web Components — Jim Nielsen
- HTML Web Components: An Example — Jim Nielsen
- HTML Web Components are Just JavaScript? — Miriam Suzanne
- An Attempted Taxonomy of Web Components — Zach Leatherman
- Messin’ Around With Web Components — Lee Reamsnyder
- The Elevator Pitch for Web Components — Chris Ferdinandi
- Web Components Are Easier Than You Think — John Rhea
- Mighty Morphin’ Web Components — Tyler Sticka
- Building an Accessible Image Comparison Web Component — Paul Hebert
- Web Components as Progressive Enhancement — Paul Hebert
- HTML With Superpowers — Dave Rupert
- Let’s Talk About Web Components — Brad Frost