Mayank RSS

"Web components" considered harmful

This is not clickbait (well, kind of1). When I say it’s harmful, I’m talking only about the name “web components”, not necessarily the actual web component APIs. I think the APIs themselves are quite useful, and we need more of them.

What are web components?

I’ll keep this short, promise.

Every tutorial you read (including my own) will tell you that web components are mainly three things:

  1. Custom elements
  2. Shadow DOM
  3. Templates

These are “web component APIs”. It’s easy to think of that term as “APIs for creating web components” but it would be more appropriate to instead think of them as “web APIs for creating components (among other things)”.

I also like the way Nathan Knowler framed it (in a private conversation):

I don’t build web components, I build using web components (APIs).

Now, I’m not interested in arguing about semantics, but this kind of reframing makes it easier to reason about when you use any of the web component APIs individually for non-component uses (which is a totally valid thing to do! These are just like any other DOM APIs that don’t prescribe how you use them).

Some strawman examples

Is the following code a “web component”? (Assume there is no other code)

Code snippet
customElements.define("my-thing", class extends HTMLElement {});
const thing = document.createElement("my-thing");
document.body.appendChild(thing);

What about the following?

Code snippet
<visually-hidden>Edit</visually-hidden>
Code snippet
visually-hidden:not(:focus-within, :active) {
  clip-path: inset(50%) !important;
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden !important;
  white-space: nowrap !important;
  user-select: none !important;
  border: 0 !important;
  margin: -1px !important;
}

How about this one?

Code snippet
<body>
  <template shadowRootMode="open">
    <h1>This is the page title</h1>
    <slot></slot>
  </template>

  <p>The page content gets slotted</p>
</body>

And finally, how about the following? (Assume there is a lot of code in “my-checkbox.js” that registers the custom element, attaches a shadow tree, associates semantics, adds styles, listens for events, etc)

Code snippet
<my-checkbox defaultChecked></my-checkbox>
<script src="my-checkbox.js"></script>

Think about it, really. What makes any of those examples more “component”-y than others? Aren’t they all using web component APIs?

Components are already a thing

JavaScript frameworks like React have already popularized “components” to the point that everyone intuitively understands what it means.

Even designers know what a component is, and I can assure you they don’t give a fuck about whatever “web components” can do.

I’ve written about components before, and even I could not find a way to fit “web components” into my definition (and I was being very lenient).

Even if you don’t use a dedicated component framework, you are probably still using the idea of components. Call it HTML partials, templates, views, or whatever else you’d like, it’s all the same thing.

Components compose

I can create an <Input> primitive component that wraps an <input> element. And I can create a <ThemedInput> component that wraps the primitive <Input>. Then someone else can take my <ThemedInput> and create a <PasswordInput> on top of it. After all of these components are resolved and initialized, the final DOM tree should really only contain a single <input> element.

The intermediate components are not (always) relevant for the DOM tree. The browser doesn’t care how the code on my website is organized. In other words, components are totally made up. That doesn’t mean components are not useful; just that they exist in a different plane. This is what makes it possible to compose all the way up to a <Page> component

I know some websites do attempt to compose all the way up to <my-page> using web component APIs. And I don’t fault them for doing that, especially if they find it works well for them.

Personally, I like to build my pages with a mostly-flat DOM tree, even if this tree is composed by hundreds of intermediate components. When I use shadow DOM, it’s usually for hiding my shame; most of the important content lives in the light DOM. This choice makes it much easier to deliver a more consistent and coherent experience to my visitors.

Components are flexible

Custom elements are great when I need a DOM hook for wiring up JavaScript logic. Similarly, shadow DOM is good when I need total isolation.

…but I don’t always need both or either of those things.

I don’t want to add an extra DOM element (which defaults to display: inline) for each component. And I can’t really create a whole page with fully isolated components. I also literally can’t achieve certain patterns with just web component APIs, like componentizing parts of my <head> for use across different pages.

This is probably the big takeaway here. Web component APIs can be useful when creating components, but they are not the complete answer. Components should be able to do a lot more than what web component APIs are capable of today.

(Now if we had HTML modules, I could maybe live without components.)

Call it what it is

This is a branding problem as much as it is an education problem. Neither the HTML standard nor the DOM standard mentions the term “web components” anywhere. And yet it’s present everywhere in documentation and learning material.2

If you go through a tutorial that teaches you “how to create a web component”, of course you’re going to think “I’ve created a web component!” And maybe that is what you’re doing, but I think this can force you into a very narrow worldview.

Perhaps the more pressing issue: the term “web components” creates unnecessary and avoidable confusion among folks who already have a preexisting notion of what components are. When they find that “web components” can’t do what they expect components to be able to do, they’ll complain about how “web components are not the future”. That’s a missed opportunity for making these APIs enticing and approachable for everyone.

So here’s a suggestion: Why not just say what you mean? We already have descriptive, well-understood, clearer names for these things:

Sometimes you might use a framework to combine these things into a “component”. But in vacuum, these are just “web component APIs” that can be individually used in any way you like.

Or you can keep saying “web components”. I’m not your boss.

Footnotes

  1. I use the words “considered harmful” in faceitious manner. I’m aware that this phrase itself is harmful if written seriously.

  2. I will happily admit that I’ve been guilty of overusing the term “web components” myself. Lately I’ve been going through some of my old writing and replacing all instances of it with more appropriate terms.