DEV Community

Rich Harris
Rich Harris

Posted on • Edited on

Why I don't use web components

For my first post on dev.to I thought I'd write about a nice, safe topic that's free of controversy: web components.

I'm mostly writing this for my future self, so that I have something to point to next time someone asks why I'm a web component skeptic, and why Svelte doesn't compile to custom elements by default. (It can compile to CEs, and it can consume CEs as evidenced by its perfect score on Custom Elements Everywhere.)

None of this should be taken as criticism of the hard work that has been done on web components. It's possible that I have made some errors in this post, in which case I'd welcome corrections.

Nor am I saying that you shouldn't use web components. They do have valid use cases. I'm just explaining why I don't.

1. Progressive enhancement

This may be an increasingly old-fashioned view, but I think that websites should work without JavaScript wherever possible. Web components don't.

That's fine for things that are intrinsically interactive, like a custom form element (<cool-datepicker>), but it's not fine for your nav bar. Or consider a simple <twitter-share> element that encapsulates all the logic for constructing a Twitter web intent URL. I could build it in Svelte and it would generate server-rendered HTML like this:



<a target="_blank" noreferrer href="..." class="svelte-1jnfxx">
  Tweet this
</a>


Enter fullscreen mode Exit fullscreen mode

In other words, a bog-standard <a> element, in all its accessible glory.

With JavaScript enabled, it progressively enhances β€” rather than opening a new tab, it opens a small popup window instead. But without, it still works fine.

By contrast, the web component HTML would look something like this...



<twitter-share text="..." url="..." via="..."/>


Enter fullscreen mode Exit fullscreen mode

...which is useless and inaccessible, if JS is disabled or somehow broken, or the user is on an older browser.

The class="svelte-1jnfxx" is what enables encapsulated styles without Shadow DOM. Which brings me onto my next point:

2. CSS in, err... JS

If you want to use Shadow DOM for style encapsulation, you have to include your CSS in a <style> element. The only practical way to do so, at least if you want to avoid FOUC, is to have the CSS in a string in the JavaScript module that defines the custom element.

This runs counter to the performance advice we've been given, which can be summarised as 'less JavaScript, please'. The CSS-in-JS community in particular has been criticised for not putting CSS in .css files, and yet here we are.

In future, we may be able to use CSS Modules alongside Constructable Stylesheets to solve this problem. And we may be able to use ::theme and ::part to style things inside Shadow DOM. But these aren't free of problems either.

3. Platform fatigue

At the time of writing, there are 61,000 open issues on https://crbug.com, the Chromium bug tracker, which reflects the enormous complexity of building a modern web browser.

Every time we add a new feature to the platform, we increase that complexity β€” creating new surface area for bugs, and making it less and less likely that a new competitor to Chromium could ever emerge.

It also creates complexity for developers, who are encouraged to learn these new features (some of which, like HTML Imports or the original Custom Elements spec, never catch on outside Google and end up being removed again.)

4. Polyfills

It doesn't help that you need to use polyfills if you want to support all browsers. It really doesn't help that the literature on Constructable Stylesheets, written by a Googler (hi Jason!), doesn't mention that they're a Chrome-only feature (edit: this has been fixed after I opened a pull request). The three spec editors are all Googlers. Webkit seem to have some doubts about some aspects of the design.

5. Composition

It's useful for a component to be able to control when (or whether) its slotted content is rendered. Suppose we wanted to use the <html-include> element to show some documentation from the network when it became visible:



<p>Toggle the section for more info:</p>
<toggled-section>
  <html-include src="./more-info.html"/>
</toggled-section>


Enter fullscreen mode Exit fullscreen mode

Surprise! Even though you didn't toggle the section open yet, the browser already requested more-info.html, along with whatever images and other resources it links to.

That's because slotted content renders eagerly in custom elements. It turns out that most of the time you want slotted content to render lazily. Svelte v2 adopted the eager model in order to align with web standards, and it turned out to be a major source of frustration β€” we couldn't create an equivalent to React Router, for example. In Svelte v3 we abandoned the custom element composition model and never looked back.

Unfortunately this is just a fundamental characteristic of the DOM. Which brings us to...

6. Confusion between props and attributes

Props and attributes are basically the same thing, right?



const button = document.createElement('button');

button.hasAttribute('disabled'); // false
button.disabled = true;
button.hasAttribute('disabled'); // true

button.removeAttribute('disabled');
button.disabled; // false


Enter fullscreen mode Exit fullscreen mode

I mean, almost:



typeof button.disabled; // 'boolean'
typeof button.getAttribute('disabled'); // 'object'

button.disabled = true;
typeof button.getAttribute('disabled'); // 'string'


Enter fullscreen mode Exit fullscreen mode

And then there are the names that don't match...



div = document.createElement('div');

div.setAttribute('class', 'one');
div.className; // 'one'

div.className = 'two';
div.getAttribute('class'); // 'two'


Enter fullscreen mode Exit fullscreen mode

...and the ones that just don't seem to correspond at all:



input = document.createElement('input');

input.getAttribute('value'); // null
input.value = 'one';
input.getAttribute('value'); // null

input.setAttribute('value', 'two');
input.value; // 'one'


Enter fullscreen mode Exit fullscreen mode

But we can live with those quirks, because of course some things will be lost in translation between a string format (HTML) and the DOM. There's a finite number of them, and they're documented, so at least you can learn about them given enough time and patience.

Web components change that. Not only are there no longer any guarantees about the relationship between attributes and props, but as a web component author, you're (presumably?) supposed to support both. Which means you see this sort of thing:



class MyThing extends HTMLElement {
  static get observedAttributes() {
    return ['foo', 'bar', 'baz'];
  }

  get foo() {
    return this.getAttribute('foo');
  }

  set foo(value) {
    this.setAttribute('foo', value);
  }

  get bar() {
    return this.getAttribute('bar');
  }

  set bar(value) {
    this.setAttribute('bar', value);
  }

  get baz() {
    return this.hasAttribute('baz');
  }

  set baz(value) {
    if (value) {
      this.setAttribute('baz', '');
    } else {
      this.removeAttribute('baz');
    }
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'foo') {
      // ...
    }

    if (name === 'bar') {
      // ...
    }

    if (name === 'baz') {
      // ...
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

Sometimes you see things go the other way β€” attributeChangedCallback invoking the property accessors instead. Either way, the ergonomics are disastrous.

Frameworks, by contrast, have a simple and unambiguous way to pass data into a component.

7. Leaky design

This point is a bit more nebulous, but it weirds me out that attributeChangedCallback is just a method on the element instance. You can literally do this:



const element = document.querySelector('my-thing');
element.attributeChangedCallback('w', 't', 'f');


Enter fullscreen mode Exit fullscreen mode

No attribute changed, but it will behave as though it did. Of course, JavaScript has always provided plenty of opportunities for mischief, but when I see implementation details poke through like that I always feel as though they're trying to tell us that the design isn't quite right.

8. The DOM is bad

Ok, we've already established that the DOM is bad. But it's hard to overstate what an awkward interface it is for building interactive applications.

A couple of months back, I wrote an article called Write less code, intended to illustrate how Svelte allows you to build components more efficiently than frameworks like React and Vue. But I didn't compare it against the DOM. I should have.

To recap, here's a simple <Adder a={1} b={2}/> component:



<script>
  export let a;
  export let b;
</script>

<input type="number" bind:value={a}>
<input type="number" bind:value={b}>

<p>{a} + {b} = {a + b}</p>


Enter fullscreen mode Exit fullscreen mode

That's the whole thing. Now, let's build the same thing as a web component:



class Adder extends HTMLElement {
  constructor() {
    super();

    this.attachShadow({ mode: 'open' });

    this.shadowRoot.innerHTML = `
      <input type="number">
      <input type="number">
      <p></p>
    `;

    this.inputs = this.shadowRoot.querySelectorAll('input');
    this.p = this.shadowRoot.querySelector('p');

    this.update();

    this.inputs[0].addEventListener('input', e => {
      this.a = +e.target.value;
    });

    this.inputs[1].addEventListener('input', e => {
      this.b = +e.target.value;
    });
  }

  static get observedAttributes() {
    return ['a', 'b'];
  }

  get a() {
    return +this.getAttribute('a');
  }

  set a(value) {
    this.setAttribute('a', value);
  }

  get b() {
    return +this.getAttribute('b');
  }

  set b(value) {
    this.setAttribute('b', value);
  }

  attributeChangedCallback() {
    this.update();
  }

  update() {
    this.inputs[0].value = this.a;
    this.inputs[1].value = this.b;

    this.p.textContent = `${this.a} + ${this.b} = ${this.a + this.b}`;
  }
}

customElements.define('my-adder', Adder);


Enter fullscreen mode Exit fullscreen mode

Yeah.

Note also that if you change a and b in the same instant, it will result in two separate updates. Frameworks don't generally suffer from this issue.

9. Global namespace

We don't need to dwell on this one too much; suffice it to say that the dangers of having a single shared namespace have been well understood for some time.

10. These are all solved problems

The biggest frustration of all is that we already have really good component models. We're still learning, but the basic problem β€” keep the view in sync with some state by manipulating the DOM in a component-oriented fashion β€” has been solved for years.

Yet we're adding new features to the platform just to bring web components to parity with what we can already do in userland.

Given finite resources, time spent on one task means time not spent on another task. Considerable energy has been expended on web components despite a largely indifferent developer population. What could the web have achieved if that energy had been spent elsewhere?

Top comments (122)

Collapse
 
equinusocio profile image
Mattia Astorino • Edited

I'm sorry, but no, most of the points you defined are extracted from a bad usage of the technology. Then:

1 is not true.
You can progressive enhance web components even with js disabled.
googlechromelabs.github.io/howto-c...

2 is not true.
You don't have to put all the style inside the shadow dom, only the style that should not be composable or accessibile. Just like private ts functions.
You have a lot of flexibility then. I suggest to check this and define the context of your web component.
css-tricks.com/making-web-componen...

Another thing, host elements are exposed and fully customizable by external css and you should work on this. Again only the private and functional/structural css should be inside the shadow tree.
codepen.io/equinusocio/pen/vMOqBO

CSS-in-JS is not a problem while you write real CSS and generate it inside a css file or embedd it inside a <style> tag. The problem of the first css-in-js tools was the fact that you had to write pseudo css json-like and put it inline. Now, any modern css-in-js solution allows you write standard css and put it inside a separated file.

3 and 4 was true until 2018
Right now all the modern browsers fully support the v1 spec. This mean all the webkit and chromium based browsers (including edge). No polyfill needed for modern development, and if you have to support old browsers you're probably already using polyfill for js things so what's the problem? You just choosed a new technology to develop for old browsers.

5 is normal and it make totally sense.

Slotted elements don't live inside the shadow-tree where you put the <slot> tag, they live in the light-dom, and as any html element in light dom (for example inside the document) they are rendered immediately. Web components are custom html element, if you want to add a lazy behaviour, you have to implement it for your component, like as you do it right now with any lazyload js library.

6 This is true for the whole HTML
These issues are related to HTML and you have them with any framework if you work with plain attributes and not on top of abstractions.


Web components are not React, Vue or Svelte components, they are not logical containers, they are true html elements that live in the document and they should be used like any other html element. Taking a web component and comparing it to an abstracted svelte component is totally misleading. They do different things.

I like sveltejs and i think it's a good framework on top of good abstraction, you don't need to write falsy things about other technologies.

I'm not here to tell web components are the solution or that they are better than other tools. But i don't like content that compare two different things and claim that one is totally bad compared to the other.

Cheers!

Collapse
 
richharris profile image
Rich Harris

Thanks for the comment. We could go back and forth for a long time saying which parts of the other's post were wrong and which were based on misunderstandings, but I'll limit myself to this: if you're saying 'this is just how it is with the DOM/HTML', then you're making my argument for me!

Collapse
 
equinusocio profile image
Mattia Astorino • Edited

If we bring the topic at this level, you have all of these problem everywhere on the web platform, independently from the tool/framework used. React, Svelte, Vue, Angular... they all work on the web platform, they work with HTML, CSS and JS and share the same platform issues. So web components too share the same issue, but they can't be compared to what you do with React or Svelte. As i wrote here web components are on a lower layer, they aren't an abstraction that generate DOM, they are HTML elements, you write real representation of the DOM (and relative issues) through new html elements, not "logical" components.

Thread Thread
 
josepot profile image
Josep M Sobrepere • Edited

Ok, so I'm a bit confused now...

If I understood what you said correctly, then you agree on the fact that web-components are just leaky abstractions built on top of other leaky abstractions, right?

Now, what you are saying is that they can't be compared with React or Svelte, because React, Svelte, Vue... do provide non leaky APIs that "hide" the platform by treating it as an implementation detail.

So, the aim of JS Component libraries is to make "the platform" an implementation detail, because we want non broken abstractions. We want to have clean contracts that allow us to encapsulate functionality, so that we can have composable and reusable things to work with, without having to worry too much about the leaky web-platform. That's (at least in part) why JS Component libraries were created, right?

But then the platform became jealous because we were "hiding" it. So one day it came out and said:

Wait a second! I see that you like to encapsulate functionality and stuff, right? But you don't have to ignore me for doing that! Please, let me create another leaky abstraction for you... Let's call it web-components! Now, please, please, please do not compare them with those things that hide my flaws. Just accept the fact that I'm broken and that I can only produce broken stuff. Just love my new broken abstraction as it is, ok? We all have flaws...

I think that I get it now. You have more compassion for the web-platform than I do. You feel sorry for it.

I have to say that I really respect your unconditional love towards the platform! But I don't share that feeling, at all.

Collapse
 
jimmont profile image
Jim Montgomery

Rich you are on point of fact incorrect on more than half of the article's points. However if figuring this out is not your aim it would naturally lead to back and forth for a long time. Not suggesting this is your aim, or that the points could not be corrected, and in a few cases are widely held misunderstandings. Your comment to back and forth suggests a very low level of interest in actually being open to figuring out how the thing really works so you might reconsider.

Collapse
 
paulmaly profile image
PaulMaly

1 is not true.
We can't render WCs on the server and WCs not work without JS enabled. Do you ever try to create an isomorphic (universal) web app using WCs? It's the hardest part even if you work with some framework on top of this.

Also, there are many problems with forms, focus/selection, SVGs, etc.

3 and 4 was true until 2018
A problem that polyfills are not the same. One thing when you need to polyfill a simple feature or maybe transpile some new language features. But WCs polyfills always worked bad because this's a thing which hard to polyfill properly. Modern browsers are great and I really love that they're supported WCs well, but we'll never get rid of old browsers.

A simple example close to me - how often you're changing your TVs? Not so often than your phone, right? Our company working with TVs and I know that most TVs in the world (I'm talking about smart TVs of course. Today it's tricky to buy a TV without this feature) comes from 2014-16 years. There are no updates, so seems we'll live with these devices a long time.

5 is normal and it make totally sense.
It makes sense but bad DX. In Svelte 2 we had many problems with this standard behavior.

6 This is true for the whole HTML
True and it's hard to reconcile with it. HTML is really old standard and it was created in a time when no one could ever imagine how we'll use it. Constraints of HTML is the weakest part of WCs.

Writing a whole web app using WCs is too hard and even impossible nowadays. Actually, it's not a choice frameworks vs WCs. The main idea to use WCs as additional HTML elements inside of frameworks templates and it's good. We can name it leaf-components or just html tags. Btw, because of Svelte uses html-first approach, it's very simple and convenient to use WCs in Svelte apps. The main problem today is the majority of existing WCs right now depending on Polymer and it's an ecosystem.

Collapse
 
webreflection profile image
Andrea Giammarchi • Edited
  • 1 You can serve both Custom Elements and built-in extends with the server
  • 3 and 4 are covered by my polyfills that work even on those TVs
  • 5 can be easily simplified
  • 6 you can have tiny abstractions on top and solve most things.

Everything is described in here:
gist.github.com/WebReflection/71ae...

Thread Thread
 
paulmaly profile image
PaulMaly • Edited

1) Actually, I've no idea what is heresy, but I already read your article. There you show up a very simple case where whole component html representation could be rendered using just props (data-attributes). It's nice, but real cases of web app and especially isomorphic web apps are harder to implement in this way.

WCs logic can be smeared in the whole component. We can't execute WC on the server without some kind of DOM emulation or without using stuff like Headless Chrome (prerender). All these solutions work not really performant.

For example, Svelte, because it's a compiler, can calculate most of the things in buildtime and in SSR mode just concatenate the strings which are very efficient.

3, 4) Perhaps your polyfills work great, but I've used official WC polyfills by Google and it work awful.

5) Your example still too simple to agree with your ideas. Even if we leave DX to the side, in Svelte 2 we lived without scoped slots. So we couldn't bound some parent component state to the slot without proxying it through a top-level component. It was making really complicated creation of the composition of components which should work as one, like Tabs or similar, because of common logic for switching tabs should be in the parent component, but styles and hide/show logic inside each tab component. I mean markup like this:

<Tabs>
  <Tab>Tab 1</Tab>
  <Tab>Tab 2</Tab>
  <Tab>Tab 3</Tab>
  <Panel>Tab 1 Content</Panel>
  <Panel>Tab 2 Content</Panel>
  <Panel>Tab 3 Content</Panel>
</Tabs>

It's impossible to implement something similar in WC without manual manipulating a slot contents. Check this example: googlechromelabs.github.io/howto-c... It's a exact nightmare.

With scoped slots we can pass a part of the state of component to the child components to give a signal which tab is active now. But unfortunately, WCs doesn't support scoped slots as any other kind of communications between parent and slotted (child) components except direct DOM manipulations which are awful.

6) What do you mean tiny? Lit-html weight is 3.5Kb which is whole Preact. Lit-element already 6.8Kb. Is it still a tiny? Heresy - 8.3Kb, Haunted - 5.1Kb. All gzipped. Are we still talking about tiny abstractions or about frameworks? All these libs based on WCs, so seems most of the work already done, but why they're weighted so damn much? Things like Preact or AppRun includes whole components system but their weight comparable. All these WCs based solutions just solve WCs problems, so seems there're just tons of these problems probably.

Thread Thread
 
webreflection profile image
Andrea Giammarchi

1) heresy-ssr is the serer side isomorphic version of heresy. I've been there already with hyperHTML and viperHTML, one of the fastest Hacker News PWAs, if not the fastest, is in viperHTML
3, 4) there is no official polyfill, only one polyfill promoted more than others. The fact Google AMP project itself used my polyfill should already put an end to "the official polyfill" meme: all Custom Elements based projects that succeeded from 2014 used my poly, 'cause it's more compatible, and lighter, and it polyfills builtin extends too.
5) you don't need scoped slots to achieve that, not sure why that use case has to be complicated at all.
6) my libraries have multiple versions: fully polyfilled so no extra anything is needed, only for latest browsers, with ES5 compatible syntax, with polyfills fallbacks to vaporware (the whole ungap.github.io story).
The only reason my libraries are around 5K, but heresy wraps them with extra goodness, which nicely fits in ~2.5K, is that my libraries comes without string attached: all browsers are compatible out of the box, including old mobile, old IEs, etc.
If I could drop every single trick used to fix MS Edge or IE issues, the Safari and Firefox gotcha with Template Literals, and all other quirks I had to fix for every browser here or there, the size would be more like 3K, but then again, as long as any helper that can be used to create with ease tons of components, without ever repeating common patterns, I'm ok in shipping everything included in about 10K and call it a day: that's sill 1/6th of React, if I remember correctly, and the more browsers evolve and fix their internal issues or vanish (IE, MSEdge), the smaller and faster my libraries will become.

On top of that, my libraries requires zero tooling to work via plain standards, that means teams can use these at any time, no toolchain requirements, and I've been in enough teams in my 20 years of programming to value this part almost more than anything else.

Add simplicity, performance, and pretty much everything based on standards, except when it's more convenient doing alternatively, you have the reason my libraries are 5 to 8K, and my poly 1 to 2K. That's the entire payload to unleash all the things the Web platform could do, and beyond (see heresy-ssr, which on cold start, which is the only first time a new template is encountered, is not super slick, but after that, rendering time goes around 0.03 milliseconds, so it's pretty damn good).

Thread Thread
 
paulmaly profile image
PaulMaly

1) Ok, so, how you render ShadowDOM on server-side?
3, 4) Maybe I just missed it. Could you please share a link to your polyfill?
5) Could you please describe how can I use WCs to implement these Tabs without scoped slots and manual dom querying in slotted content? I really want to enjoy your solution.
6) Seems, now I know why I not heard about heresy. I see the first release was in April. If it's good as you describe, it should become really popular. So, let's give it some time and will get in touch later to discuss it. ;-)

Collapse
 
oenonono profile image
Junk • Edited

I assure you that we will be rid of old browsers one day. People said this about IE 5 and IE 6 and when was the last time you supported IE 8?

IE is the slowest to fall out of usage, but eventually it does. Every. Single. Time.

There are plenty of real problems, no need to grasp at straws.

Thread Thread
 
paulmaly profile image
PaulMaly

I believe you missed my point about TVs. If someone bought TV in 2017 he'll change it after 10 years, maybe later. So, we'll need to support it in the next 8 years. It's called never.

Thread Thread
 
oenonono profile image
Junk

What? That doesn't make even the slightest bit of sense. Are you saying 10 years is "never"?

It's clearly 10 years.

Thread Thread
 
paulmaly profile image
PaulMaly

I mean, 10 years ago we didn’t know what’s SPA, nor Angular, WCs was no trace yet. After 10 years WCs may not be already. 10 years is infinity for web development.

Thread Thread
 
oenonono profile image
Junk

Your perspective is valid, but not complete. Look wider. In 2009 there were things like SPAs, it just wasn't as formalized and the term just wasn't coined yet.

I've been doing web development for 20 years. My career has not been two times infinity years long. If it had I'd think you'd listen to me about this. I'd be effectively God.

Collapse
 
hyperpress profile image
John Teague

This says it better than I did yesterday. Thanks.

Collapse
 
equinusocio profile image
Mattia Astorino

Do you have a link?

Thread Thread
 
hyperpress profile image
John Teague

Started here in Twitter land twitter.com/Rich_Harris/status/114..., and of course ballooned from there.

Collapse
 
tracker1 profile image
Michael J. Ryan

I actually don't mind the object/json style syntax so much... I use react-jss via material-ui mostly, and that generates the appropriate stylesheet and adds it to the header. I've played with abstracting it out, but including it in the JS payload works for the applications (not public sites) that I mostly work on.

Collapse
 
netalex profile image
Alessandro Aprile

on #8: braille browser and text browser?

Collapse
 
ben profile image
Ben Halpern

For some more interesting discussion, this is a good thread:

(The title is me reporting on the sentiment of others, I haven't necessarily made up my mind on all of this)

@dan_abramov's comment:

A few quick points from my perspective. (I work on React.)

  1. We're not opposed to supporting web components better. The problem is that there's no single "web component community". There are multiple subcommunities. You mention "web component libraries" in the post. These libraries don't agree on a single standard so React would need to pick a side in debates like "how does server rendering work with web components". Whatever we pick will have large downstream effects, and our reluctance to support more has to do with being careful (see [1] note below) about the semantics β€” not somehow being at odds with web components per se.

  2. As I mentioned in the previous point (and you mentioned in the post), there are multiple "web component libraries". As far as I can see many of the criticisms of React would apply to such libraries as well. I don't think the way to counteract "DOM FUD" is to introduce "library FUD". If you're using a library for defining and updating your web components declaratively, you're not following a conceptually different approach from using React.

  3. Saying "you can do everything with WCs that you can do in React" is double edged. Yes, of course, you can do anything β€” because we haven't actually agreed upon any constraints. If the constraint is "you don't use a React-like library on top" I think you'll find there's plenty of things that are very hard to do with an imperative abstraction like vanilla WC APIs. We've done a few talks about what using React as a unifying abstraction lets us do (such as non-blocking rendering, or dynamically loading UI code without degrading user experience). You might want to check them out (youtube.com/watch?v=nLF0n9SACd4, youtube.com/watch?v=ByBPyMBTzM0). Of course, you can do these things if you use a library like React on top of WCs. But that negates the argument that you don't need React-like libraries for this.

To sum up: we'd be happy to support WCs better in React. We don't want to rush it, and want to make sure this support is well thought-out. Additionally, we believe there are many things that raw imperative WC APIs don't give you β€” and for them something like React would be appropriate even in a WC world. Finally, there's this myth going around that once you write React code, you can't reuse it as web components. That's not true β€” and as you can see from the documentation it's a few lines of code: reactjs.org/docs/web-components.ht...

Hope that makes sense, and provides some additional context!

[1]: For example, if I'm not mistaken, the semantics chosen by Preact make introducing a new standard property to DOM base element potentially a breaking change for the web. We try to avoid such problems if possible β€” precisely because React did learn from MooTools and we don't want to do another mistake like what happened with Array.prototype.flatten().

Collapse
 
nopatternaaron profile image
aaron hans

This is a good article and I love your work on svelte and with the NY Times.

I got interested in Web Components when working at a large company maintaining several web applications built with different frameworks. It was fun to be able to create separate, lightweight components that could upgrade pieces of different applications without taking on the responsibility of rewriting too much at a time. When we used Web Components we skipped the shadow DOM because of some issues with forms that cross the light and shadow barrier and the weight of the shadow DOM polyfill. We namespaced our component's CSS rules by prefixing them with the custom element name during a build step. Skipping the shadow DOM also allowed us to do server side rendering of our web components relatively easily using jsdom on an AWS Lambda.

I currently use Web Components at a small startup where we create a search widget government websites embed into their pages. We can deliver a small code footprint which encapsulates a ton of functionality with easy integration steps that supports browsers down to IE11.

Neither of these cases refute your points but they are common examples where Web Components shine.

Collapse
 
richharris profile image
Rich Harris

Thank you β€” yep, there are definitely cases where they shine. It's interesting that you had those issues with shadow DOM β€” in the early days, shadow DOM was kind of the whole point of web components, but I've seen a lot of people back out for similar reasons. Now we see long-running debates about where and whether to use shadow DOM, and whether a given thing belongs in shadow DOM or light DOM. Feels like that distinction has created a lot of extra complexity.

Collapse
 
webreflection profile image
Andrea Giammarchi

Shadow DOM is controversial because it plays bad with SSR, and its polyfill is not really specs compliant.

To style Custom Elements you also don't need anything different than you do already, and surely you don't need Shadow DOM at all to have Custom Elements.

Maybe Shadow DOM was sold as the true Web Components must do magic, but since 2014 I've never used it, and never needed it.

We ship Custom Elements to dozen million users, and we never used once attachShadow.

TL;DR the debate about Shadow DOM is pretty simple: don't use Shadow DOM if you target legacy browsers without native Custom Elements V1 support, or use very constrained and simple variants of the spec, like the attachshadow library that works down to IE9.

Collapse
 
oenonono profile image
Junk

Shadow DOM is my favorite part, despite its problems. Custom Elements are just interface for me. I get so much use out content distribution. It's the most important part other than style scoping.

Collapse
 
steveblue profile image
Stephen Belovarich • Edited

I agree with some of the points here about WC implementation but I don’t agree with the presentation.

3) is irrelevant. Spec is and should be a living document so naturally we’ll have to change as spec changes. We should be critical of spec. There is an opportunity to change because it is a living document.

4) I haven’t used a tool in the past decade that didn’t require a polyfill at one time or another. It’s true browsers should implement custom elements uniformly and they don’t, including custom elements v1. Browser vendors could definitely get better at this. I don’t think this argument holds weight if literally any level of sophistication in web development requires a polyfill.

10) Yes, but the nasty side effect is multiple component models leads to division in the greater web community. That’s a problem we don’t talk about enough. We have an opportunity to learn and grow together but can’t when everyday a new library comes out. So instead of Platform fatigue we end up with JavaScript fatigue. I’m not talking about Svelte necessarily, I actually think Svelte is a novel reaction to other JS libraries. The other side effect is no one bothers to learn DOM or vanilla JS because at an early stage in their education they become reliant on the popular JS library. That’s not good for anyone. We end up with a ton of engineers who don’t know how things work under the hood.

8) is so reductive I don’t know where to start. If DOM is bad, then why go into web development? We should just stop everything. Everyone go home. DOM is bad.

Web Components IMHO should have a framework wrapper to make problems like you talk about go away. That doesn’t make them bad, that is the function of every JS library. Make DOM easier to work with. No news there.

Rich, instead of bashing technologies like this perhaps it’s better for everyone if you extol the virtues of Svelte in a context that does address the limitations of DOM, but please frame it in a way that is less divisive.

Collapse
 
webreflection profile image
Andrea Giammarchi

Web Components IMHO should have a framework wrapper

I guess that's Polymer, but they kinda failed at selling WCs too.

My approach is still Custom Elements based (no umbrella, just the juicy bit), and tiny wrapper to simplify every task mentioned in here.

You can find more in this gist of mine πŸ‘‹

Collapse
 
rhymes profile image
rhymes

what about Stencil?

Thread Thread
 
webreflection profile image
Andrea Giammarchi

The moment you need tools to make anything work at all, it's the moment you are already far away from Web standards, and you are allowed to do whatever you want, like in Svelte, and other libraries, case.

Stencil One does not compete with standards anymore, rather with React/JSX, IMHO.

Thread Thread
 
rhymes profile image
rhymes

Isn't Stencil just a layer on WebComponents, like Polymer?

Thread Thread
 
webreflection profile image
Andrea Giammarchi
Thread Thread
 
steveblue profile image
Stephen Belovarich • Edited

Stencil is the best option by far for design systems.

Thread Thread
 
webreflection profile image
Andrea Giammarchi

I'd give πŸ”₯ heresy πŸ”₯ a chance too, it works out of the box on client/SSR and since it needs zero real DOM to work, it might easily end up on NativeScript or similar too πŸ¦„

Thread Thread
 
rhymes profile image
rhymes

The article keeps saying Stencil compiles to Web Components, that's what I meant πŸ˜…

Yeah it's more than that but the final product is WC.

Anyway, frontend has so many tools 😬😬😬😱

Thread Thread
 
webreflection profile image
Andrea Giammarchi • Edited

hello world example

almost nothing you see in that definition is standard:

  • decorators are not there yet
  • @Prop() first: string; makes literally no sense on JS
  • the JSX return in the render also makes no sense

Stencil One is basically the most hybrid thing of them all, and once it compiles to "standrd JS", it needs a global defineCustomElements to be useful at all.

One can't really ship portable components like this, or can they?

The good news, is that it might target also NativeScript or similar platforms (I'd imagine React native, due JSX in the render), but the bad one is that Stencil One is far away from being a standard based way to develop anything, 'cause it needs, for those parts, mandatory toolchain that is not part of standard Web development.

I hope I've clarified a bit more, happy to answer further, if necessary.

Thread Thread
 
rhymes profile image
rhymes

I hope I've clarified a bit more, happy to answer further, if necessary.

Ok got it, I thought that Stencil's output was just pure web components, that's it.

Thread Thread
 
briancodes profile image
Brian • Edited

The props and decorators are removed during compilation, and the output is a Web Component. There's a lot of companies building design systems now with Stencil dev.to/ionic/apple-just-shipped-we...

Collapse
 
steveblue profile image
Stephen Belovarich

I made a feeble attempt here too.

readymade-ui.github.io/readymade/

Collapse
 
sebbdk profile image
Sebastian Vargr • Edited

The other side effect is no one bothers to learn DOM or vanilla JS because at an early stage in their education they become reliant on the popular JS library.

I know this is an old comment, but i would like to thank you for recognizing this issue.
I hope more people start thinking about this problem.

Collapse
 
ben profile image
Ben Halpern

I agree with a lot of this, but also feel like the jury is still out on some of it as well. My approach, luckily, is to wade in shallow water and see where things go. I would be nervous about getting too deep into webcomponents.

Though I know this is bound to create debate.

Collapse
 
akirodic profile image
Aki Rodić

I respectfully disagree with most of your arguments. I understand that some of the features of the platform frustrate you. Lets start from the beginning.

1 Progressive enhancement) If you think that websites should work progressively even in browsers without javascript, then web components are not for you. I'd say even the older browsers such as IE are not really suitable for web components. Sure, you can use polyfils but that defeats the purpose. So lets get this out of the way, web components are only meant to be used in browsers that natively support them (and also support javascript).

2 CSS in, err... JS) I gotta say I do agree with problems of CSS encapsulation in Shadow DOM. That is why I don't use the Shadow DOM and its the least favorite feature web components to me. Still I don't mind that it is there, and I'm sure it will be useful in some cases. As for having CSS in files that don't have .css extension... you are free to put your CSS wherever you want, you can also put it in you html file. There is nothing in web components preventing you to do it the old-fashioned way. It is just more convenient to develop in a modular way and have code organized a bit differently even if it means <style> strings in your js. Personally, I like it.

3 Platform fatigue) Totally right. It would be much easier for browser developers if no new features are added. It was much easier when we had Adobe Flash. On the other hand, it was Adobe Flash.

4 Polyfills) Also agree (see point 1). Never use polyfills. Web components should be used only on browsers that natively support it. If you are developing a product that needs to work in IE, do not use web components. Period.

5 Composition) This is not really a web component feature. Its just how DOM works. The problem you solved with svelte, you can still solve using custom elements. Also, this is a problem to be solved on a higher level application framework/library. Alternatively, you can make a custom element that solve this problem for you and then reuse it.

6 Confusion between props and attributes) Again, this is not specific to web components. It sucks and I know. It also sucks that attributes are so expensive in general compared to properties. Personally, I developed my framework to rely mostly on properties and ignore attributes by default because in most cases I don't use them. Sometimes I reflect properties to attributes but only as a CSS selector. Almost never do I listen to attribute changes, but in some rare cases I do. Focusing on properties only, helps with this problem a lot.

7 Leaky design) Not a significant issue.

8 The DOM is bad) It is also good. So is CSS.

9 Global namespace) Since you can only register one element of the same name, I think this kind of makes sense.

10 These are all solved problems) If you really believe that, there is no argument to make you think otherwise. I think it comes down to what you think web applications should be capable of. Personally, I think web should one day be able to do everything that native platforms do except: better, faster, more efficient, with better user and developer experience.

A lot of people see web as a platform for static documents with hyperlinks as it once was while others see it as the future of computation. Where on this spectrum are you? According to your writings, I'd guess somewhere in the middle leaning towards former.

Collapse
 
hyperpress profile image
John Teague • Edited

This sounds so much like a framework author saying mine is better, web component and their libraries don't measure up. Again, this points to turf more than facts. Why feel the need to throw trash in someone else's backyard, while praising your own. I've said that svelte addresses solutions be it in it's own way. If you like it, use it. And I make that recommendation sincerely. Not with "I'm not saying you shouldn't use web components, but here's why they're a bad solution.

Collapse
 
richharris profile image
Rich Harris

The headline of this post is 'Why I don't use web components'. And I clearly say that I'm explaining my personal choices. But sure β€” if you don't think the substantive criticisms I've raised are important, then I'm not going to waste energy trying to change your mind.

Collapse
 
hyperpress profile image
John Teague

Okay, Rich.

Collapse
 
stevenvachon profile image
Steven Vachon • Edited

I think you're approaching web components from the wrong perspective. They are not yet complete and as such are not yet suited for architecting a vanilla application. They are, however, very useful in small, reusable cross-framework libraries.

I'll address each of your points:

  1. How much progressive enhancement do you need when the app's JS is either not available (disabled) or still being downloaded? I think that CSS' :defined pseudo-class is sufficient for styling the light tree of an element that hasβ€”or will haveβ€”a shadowRoot. You can also use a fallback design such as <select is="super-list">.

  2. What "problems" does ::part() have?

  3. Um, yeah, let's not move the web platform forward. Drivel.

  4. No one said that you should use web components for a project that supports IE9/etc. You'd have a ton of polyfills already for that target and probably terribly outdated CSS practices if not using terrible CSS polyfills.

  5. Using existing web components today would still require some form of a wrapper to nicely handle data wiring, and with that, you'd probably have something to handle templating. In which case, this point is a non-issue.

  6. You don't have to write components this way, but it is nice and complete to be consistent with standard elements. See my thoughts at the very top of this comment.

  7. Maybe it will support private methods when that proposal is stage 4. Not a big deal.

  8. See my thoughts at the very top of this comment.

  9. I can see how this could be an issue for architecting an application. However, see my thoughts at the very top of this comment.

  10. They're solved with tools that are not part of an official specification which serves the entire web community. Such frameworks serve opinionated sub-communities. The web component specification has always been taking the best ideas from these frameworks and will continue to do so until we no longer need any of them.

Collapse
 
thatferit profile image
Ferit πŸŒŸπŸ•Œ

Isn't the push for Web Components mainly coming from one big browser vendor as some sort of "owning the web", as now developers moved on to non-Google tooling ?

I have the observation that the push for some web standards is also a commercial one. If only Chrome moves heavily into that direction and the rest (safari, firefox) is doing it more cautiously we will end up again in a weird situation where:

  • Hype driven developers produce applications only for Chrome,
  • the rest is getting "Move to Chrome" Banners...

It is not proven by data, yet I see many non-googlers sharing doubts about WC vs. Googlers talking about it as the "only good solution".

Collapse
 
equinusocio profile image
Mattia Astorino

This is a widley discussed spec. Chrome was just the first vendor implementing the spec v0 and made polyfills. Other vendors refused to implement a draft spec and they all waited for the v1. Now is widely accepted and implemented. No one forced people to use web components v0 or polymer...

Collapse
 
thatferit profile image
Ferit πŸŒŸπŸ•Œ

As I argued,

If a big Browser vendor who owns the biggest search engine, has one of the largest resources and blogs to push topics, pushes it, people will jump on that.
I used worked on multiple projects in the past with shadow dom v0 , native WCs and polymer.
Developers (Humans) are as much as everyone bound to their Bias, FOMOs etc. so it is not about actively forcing but passively pushing. I think you just undervalue the power of influence and hype in developer communities.

Thread Thread
 
equinusocio profile image
Mattia Astorino

I think hype is just a question of self-control. But you're right, not everyone can remain outside the hype-loop

Thread Thread
 
dmitriid profile image
Dmitrii 'Mamut' Dimandt

Including Google themselves. They re-implemented the whole of Youtube with v0 spec which now causes problems in some browsers.

Thread Thread
 
alangdm profile image
Alan DΓ‘valos

This is no longer true, youtube has already migrated to Polymer v3 which is based on the v1 web components standards so it no longer has any problems with the latest versions of all browsers (except edge but that's already not a problem as long as you use the chromium-based build)

Collapse
 
hyperpress profile image
John Teague

If Google had that much "push" we'd still be using HTML Imports. There's no Google conspiracy, and getting agreement to ship a change is daunting, it's open to public comments and suggestions.

Collapse
 
oenonono profile image
Junk

No. Specifications only become recommendations when MULTIPLE VENDORS implement them.

Every major browser vendor gave input to and agreed to Web Components.

The web community and web standards have been working on how to allow developers to extend HTML for at least 20 years.

That is what Custom Elements are.

Collapse
 
hyperpress profile image
John Teague

I mean the whole thing started with MS HTC and FF XBL. So the idea of web components goes way back.

Collapse
 
seanmclem profile image
Seanmclem

You lost me at "websites should work without JavaScript wherever possible"...
Just wow

Collapse
 
stephenpaul profile image
StephenPaul

I agree with your sentiment here, except if accessibility is important to you.