Total pos 11658+

[Go Make Things] Progressively enhancing a Web Component

This week, we've looked at how Web Components are different from React, how to create your first Web Component, and how to add options to a Web Component.

Today, we're going to look at one of my favorite Web Component features: progressive enhancement.

Let's dig in!

A few different approaches

There are two different ways to progressively enhance a Web Component (there's probably more, but these are the two I use most often)…

  1. If the content only works with JavaScript, hide it, and only show it after the Web Component instantiates.
  2. If the content works without JavaScript, show a default HTML experience, and then layer in additional HTML and JavaScript-based interactivity after the Web Component instantiates.

In this article, we'll look at both approaches, and when and why to choose one approach over the other.

Approach 1. Hide the content

For this approach, let's look at the example we've been using all week, our <wc-count> component that creates a counter button.

<wc-count>  	<button>Clicked 0 Times</button>  </wc-count>

Here, the button does absolutely nothing without JavaScript. As a result, it probably makes sense to hide it entirely until the Web Component is ready.

There are a few ways to do that…

Using the [hidden] attribute

One way to do that is by slapping a [hidden] attribute on the element.

<wc-count hidden>  	<button>Clicked 0 Times</button>  </wc-count>

Then, in our constructor() method, we can remove the attribute when instantiating the component.

/**   * The class constructor object   */  constructor () {    	// Always call super first in constructor  	super();    	// ...    	// Show the element  	this.removeAttribute('hidden');    }  

Using CSS

The :defined pseudo-class provides another way to detect when a custom element has been defined using just CSS instead of JavaScript.

We can combine it with the :not() pseudo-class to hide our custom element until it's defined.

/* Hide the <wc-count> element until it's defined */  wc-count:not(:defined) {  	display: none;  }

With a fallback message

It might be a good idea to load a fallback message while the content is loading.

Here, I've wrapped that content in a <wc-count-loading> custom element, and added the [hidden] attribute to the <button> element instead.

<wc-count>  	<button hidden>Clicked 0 Times</button>  	<wc-count-loading>Loading...</wc-count-loading>  </wc-count>

Then, in the constructor() method, I remove the [hidden] attribute from this.button. I also use the Element.querySelector() method to get the <wc-count-loading> element, and the Element.remove() method to remove it once the content is ready.

/**   * The class constructor object   */  constructor () {    	// Always call super first in constructor  	super();    	// Instance properties  	this.button = this.querySelector('button');  	// ...    	// Show the element  	this.button.removeAttribute('hidden');  	this.querySelector('wc-count-loading')?.remove();    }  

Approach 2. Layering in HTML and interactivity

This approach works great when you have content that stands on its own, but benefits from some added flourish or interactivity.

For example, let's imagine you're creating an accordion group, with different expand/collapse sections.

You can start this off with HTML that includes headings and content, like this…

<accordion-group>  	<h2>Why is Lil' Wayne hip-hop top 5 list?</h2>  	<div>  		<p>...</p>  	</div>    	<h2>How many spells could Merlin cast in a day?</h2>  	<div>  		<p>...</p>  	</div>  </accordion-group>

When you instantiate your Web Component in the constructor() method, you can then update the UI to hide or show elements as needed, inject additional HTML, add required attributes, and so on.

/**   * Instantiate the Web Component   */  constructor () {    	// Get all accordion headings  	let headings = this.querySelectorAll('h2');    	// Update content  	for (let heading of headings) {    		// Get the matching content  		let content = heading.nextElementSibling;  		if (!content) continue;    		// Create a button, and copy heading content into it  		let btn = document.createElement('button');  		btn.innerHTML = heading.innerHTML;    		// Wipe the heading content, and replace it with the button  		heading.innerHTML = '';  		heading.append(btn);    		// Hide the content  		content.setAttribute('hidden', '');    		// Add ARIA  		btn.setAttribute('aria-expanded', false);    	}    }  

You end up with HTML that looks something like this…

<accordion-group>  	<h2><button>Why is Lil' Wayne hip-hop top 5 list?</button></h2>  	<div hidden>  		<p>...</p>  	</div>    	<h2><button>How many spells could Merlin cast in a day?</button></h2>  	<div hidden>  		<p>...</p>  	</div>  </accordion-group>

Which approach should you use?

I favor starting with base HTML and layering in interactivity whenever you can.

If I have content that simply does not work with HTML and has no base-level experience, I'll try to include a fallback message until the Web Component loads, but otherwise hide the content.

Like this? You can support my work by purchasing an annual membership.

Cheers,
Chris

Want to share this with others or read it later? View it in a browser.

Post a Comment

Previous Post Next Post

.

Sponsor/Ad.Iklan :
Diamond free fire & mobile legens bang bang
tempat beli Pulsa pakai paypal





Search.Pencarian
Menu

Add text send email to rh3252705.adda@blogger.com or Click this (Text porn Will delete) | Tambah teks kirim email ke rh3252705.adda@blogger.com atau Klik ini (Teks porno akan dihapus)
Total post.pos : 8900+