Instantly share code, notes, and snippets.

Embed
What would you like to do?
A Criticism of Web Components

This is a repost of my (now deleted) comment on SitePen https://www.sitepen.com/blog/2018/07/06/web-components-in-2018/ I've added some additions and references.

A similar comment of mine was removed from the Mozilla blog: https://hacks.mozilla.org/2018/11/the-power-of-web-components

It seems that The Emperor has no clothes...


A Criticism of Web Components

"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 psuedo 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:

HTMLFormElement.elements
HTMLFormElement.length
HTMLFormElement.autocomplete

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:

https://w3ctag.github.io/webcomponents-design-guidelines/ https://github.com/webcomponents/gold-standard/wiki

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:

<my-foo>
    <my-bar></my-bar>
</my-foo>

Are your fallbacks compositional?

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

Is that right? Maybe more so like this?

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

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>
</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 requirments 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 libary (especially Firefox and Microsoft Edge)

  • SLOOOOW at scale (10+ components). There is a singificant amount of DOM Mutation listening going on behind the scenes

  • Other issues

  • HTML Imports are now deprecated, so that particular polyfill may not be around in the future

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:

https://lists.w3.org/Archives/Public/public-webapps/2014JulSep/0355.html

Additional Limitations

https://github.com/webcomponents/gold-standard/wiki/Web-Component-Limitations

Conclusion

While I have high 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 for others to see. As time goes on I hope this gist can be thrown in the dustbin of history.

@mlhaufe

This comment has been minimized.

Copy link
Owner

mlhaufe commented Aug 21, 2018

Added an explicit reference to the polyfill size based on feedback from @adamdbradley

@mlhaufe

This comment has been minimized.

Copy link
Owner

mlhaufe commented Sep 14, 2018

HTML Imports are now deprecated. I hope you weren't relying on that particular polyfill...

@mlhaufe

This comment has been minimized.

Copy link
Owner

mlhaufe commented Nov 15, 2018

Added a reference to the news that Google is planning to disable JavaScript by default on 2G connections

@mlhaufe

This comment has been minimized.

Copy link
Owner

mlhaufe commented Dec 24, 2018

Added referenced to the new best practices guidelines as well as the Additional Limitations section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment