Skip to main content Accessibility Feedback

HTML Web Components

Last week, Jeremy Keith wrote about what he calls HTML Web Components.

Some people treat Web Components like JS library components, where everything is rendered with JavaScript. But Jeremy has a different suggestion…

Try not to bring React’s mindset with you…

Think about composibility with existing materials. Do you really need to invent an entirely new component from scratch? Or can you use HTML up until it reaches its limit and then enhance the markup?

…If your custom element is empty, it’s not an HTML web component. But if you’re using a custom element to extend existing markup, that’s an HTML web component.

I got to experience the power of HTML Web Components first-hand this week.

I’m building an app for NASA.

👋 Quick note: If you’d like to work with me, I have one consulting spot left.

The backend engineer has built a powerful, simple backend using Python. Every single user interaction is either a link that points to an actual HTML file, or a form that submits data to the server, then redirects to a server-rendered HTML file.

The whole thing works without a single drop of JavaScript!

I wanted to preserve that deep level of resilience and accessibility by progressively enhancing the existing functionality rather than doing all the things with JavaScript.

My initial approach: traditional DOM manipulation

I originally went down a path of listening for submit events on the document, and running different callback functions for different forms…

// Hold the various form handler functions
let handlers = {
	addItem (event) {
		// ...
	},
	removeItem (event) {
		// ...
	},
	combineItems (event) {
		// ...
	}
};

// Listen for submit events
document.addEventListener('submit', function (event) {
	let id = event.target.getAttribute('data-form');
	if (!handlers[id]) return;
	handlers[id](event);
});

Each event handler would show some status messages, then either redirect the user to another page, or display some success message in the UI and add or remove a list item from the UI.

This worked, but as the number of interactions grew, so did the complexity and size of this setup.

There was a lot of not-so-DRY code, so I abstracted some of it. That reduced the repetitive code, but also made the code less readable and even more complex.

Then, I had an epiphany.

Just use a Web Component!

I ended up refactoring my first attempt into an HTML Web Component.

The ajax-form component wraps around a form element. By default, the form submits to the server, just like normal. Once the Web Component initializes, it enhances the form.

<ajax-form>
	<form method="post" action="/subscribe">
		<label for="email">Add your email to join the newsletter</label>
		<input type="email" id="email" name="email">
		<button>Join</button>
	</form>
</ajax-form>

What I love about Web Components is that you can easily customize behavior with custom attributes.

With the [prevent-default] attribute present, the Web Component will stop the form from redirecting the page. The [msg-*] attributes let you customize the submitting, success, and error messages.

And if you need to update a portion of the UI, the target attribute will find the element with that same selector in the HTML that the fetch() request returns, and replace the existing element in the UI with the updated one.

<ajax-form 
	prevent-default 
	msg-submitting="Signing up..." 
	msg-success="Congrats! You're on the list!"
	target="#item-list"
>
	<form method="post" action="/subscribe">
		<label for="email">Add your email to join the newsletter</label>
		<input type="email" id="email" name="email">
		<button>Join</button>
	</form>
</ajax-form>

This approach let me slash the JavaScript used for this project in half, easily progressively enhance the UI, and provide an authoring approach that’s much easier to read and make sense of.

Web Components FTW!

For a while, I struggled to see the value in Web Components.

And the reason, I’ve come to realize, is that I was locked into “JavaScript component” thinking. By treating them as enhanced HTML, everything starts to click in a way that it didn’t before!

I can’t wait to use them more on future projects.