A Criticism of Web Components

This is a repost of my (now deleted) comment on SitePen. I’ve added some additions and references. A similar comment of mine was removed from the Mozilla blog.

It seems that The Emperor has no clothes

“Safe upon the solid rock the ugly houses stand: Come and see my shining palace built upon the sand!”

– Edna St Vincent Millay

Sadly there are significant issues with the standards still in many places, and many undefined behaviors.

# CSS pseudo selectors don’t work

Did you create your own form component such as <calendar />?

Well the :checked selector won’t find it unless you happened to have hidden inside of it the right native <input/> to catch it. It’s then up to you to get that to actually “check” the right parts of your UX.

Want something more semantic and relevant to your component like :focusable? Too bad. you can’t define your own as that is not part of any standard. The closest is the following which is barely a draft standard

# Incompatible with native elements

If you have a custom input element the surrounding <form> ignores your component so you may have to create <my-form/> too, or add extra logic to the native one to simply recognize your new element.

Alternatively you have to dynamically hack your custom element to inject, update, and remove a hidden input field for every relevant value just so the container will get the right value. This won’t cover other issues such as the other DOM properties which ignore your components:


new FormData(form)

and so on.

# Non-trivial elements HAVE to extend HTMLElement

It sucks to say the least to have to re-invent something like <button /> from scratch instead of a more specific element such as HTMLButtonElement but the current standard requires that you extend the base HTMLElement

Even IF you COULD extend a more specific element directly, not all elements have a class to extend, like <footer />. So you have to use the hacky property in registration, extends:

customElements.define('custom-footer', CustomFooter, {extends: 'footer'});

The built-in tags were never designed to be extended, and if you tried you will probably break Liskov’s Substitution Principle now or later. For example, if you could extend HTMLInputElement your new element has to support all of the current type="…" options, properties, and methods. When the standard changes and they add a new property or method, your subtype will be inconsistent with it and by definition NOT be an instance of HTMLInputElement. As a result of this, there is now a large set of guidelines published for you to deal with. A hallmark of poor design:

# JavaScript required

In the age of ServiceWorkers and offline-support, I don’t know how much this matters to you, but it is still a valid point for some. WebComponents simply don’t work without JavaScript enabled, so if that matters get ready to develop some fallback content for graceful degradation for each element, or for the entire page; or, get ready to write some bootstrap code to find and replace/upgrade some elements with your updated code. In either case you’re not saving yourself any time nor code writing.

Update: Chrome for Android may start disabling JavaScript on 2G connections

# Potentially exponential fallbacks

WebComponents, like other HTML elements, are compositional by nesting:


Are your fallbacks compositional?

    <div class="my-foo-fallback"></div>
        <div class="my-bar-fallback"></div>

Is that right? Maybe more so like this?

    <div class="my-foo-fallback">
            <div class="my-bar-fallback"></div>

That doesn’t seem right either… And this is with only TWO contrived tags.

Now, you might say that is why the is="" attribute exists:

<div is="my-foo">
    <div is="my-bar"></div>

Looks good at first for something trivial, but this is a hack and once you add in the Shadow DOM you’re back in the same situation.

# Polyfills required

  • These are all DRAFT standards, so for a consistent experience you’re going to probably polyfill.
  • The polyfill is potentially 100kB+ in size based on your support requirements and has a good chance of conflicting with your Content Security Policy (a lot of dynamic style manipulation).
  • Your component will render differently across browsers due to the polyfill.

In my experience the child selector is unreliable (>) due to the intermediate html elements injected by the library (especially Firefox and Microsoft Edge)

  • SLOOOOW at scale (10+ components). There is a significant amount of DOM Mutation listening going on behind the scenes
  • Other issue
  • HTML Imports are now deprecated, so that particular polyfill may not be around in the future.
    • Update: YouTube was broken due to this.

# Aria

I already mentioned earlier that you have to re-add Aria roles for the custom version of elements you’re creating, but in addition, there is no encapsulation of Aria declarations for your component:



Assuming you were able to get Aria figured out in a reasonable manner does not automatically mean it will be “accessible” to search engines (go figure). @check_ca discovered recently that Google does not do well with indexing heavy WebComponent sites. His search around April 25, 2019 yielded the following:

WebComponent Search results

Slightly later when I attempted the same search (April 29, 2019):

WebComponent Search results

Reviewing the source code of one of these pages (holy shitballs):

WebComponent Search results

<dom-if/> ? Really? Well, I’m not going to go into why that’s a terrible idea in this post. Gilad Bracha has already criticized this in the following article sufficiently. Back to SEO:

I’m going to assume this is simply growing pains for search engines. They’ve had to deal with worse in the past with Java Applets, Silverlight, and Adobe Flash. Though I can’t help but point to a weekend project I did in 2012 with XML+XSLT for much better effect. The Skechers site and a World of Warcraft site did similar.

# Additional Limitations


# Conclusion

While I have hopes for this standard, I’ve been burned too often to suggest it to anyone. I’d say wait to see if the current native elements could be implemented as WebComponents, otherwise be prepared to potentially be doing it yourself. If you’re going to go down that path you might as well throw it all away and just build yet another web framework fully suited to your needs. Feel free to add comments, workarounds, and updates on your frustrations and efforts. As time goes on I hope this post can be thrown in the dustbin of history.

# Additional Reading


You can create, reply to, and manage comments on GitHub