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>
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="..."/>
...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>
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
I mean, almost:
typeof button.disabled; // 'boolean'
typeof button.getAttribute('disabled'); // 'object'
button.disabled = true;
typeof button.getAttribute('disabled'); // 'string'
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'
...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'
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') {
// ...
}
}
}
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');
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>
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);
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 (121)
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!
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!
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.
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:
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.
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.
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.
Everything is described in here:
gist.github.com/WebReflection/71ae...
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:
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.
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).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. ;-)
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.
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.
What? That doesn't make even the slightest bit of sense. Are you saying 10 years is "never"?
It's clearly 10 years.
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.
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.
This says it better than I did yesterday. Thanks.
Do you have a link?
Started here in Twitter land twitter.com/Rich_Harris/status/114..., and of course ballooned from there.
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.
on #8: braille browser and text browser?
For some more interesting discussion, this is a good thread:
Why the React community is missing the point about Web Components
Ben Halpern ・ Nov 7 '18 ・ 1 min read
(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.)
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.
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.
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!
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.
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.
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.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.
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.
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 👋
what about Stencil?
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.
Isn't Stencil just a layer on WebComponents, like Polymer?
not at all infoq.com/news/2019/06/stencil-ion...
Stencil is the best option by far for design systems.
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 🦄
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 😬😬😬😱
almost nothing you see in that definition is standard:
@Prop() first: string;
makes literally no sense on JSStencil 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.
Ok got it, I thought that Stencil's output was just pure web components, that's it.
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...
I made a feeble attempt here too.
readymade-ui.github.io/readymade/
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.
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.
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.
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.
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.
Okay, Rich.
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:
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—ashadowRoot
. You can also use a fallback design such as<select is="super-list">
.What "problems" does
::part()
have?Um, yeah, let's not move the web platform forward. Drivel.
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.
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.
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.
Maybe it will support private methods when that proposal is stage 4. Not a big deal.
See my thoughts at the very top of this comment.
I can see how this could be an issue for architecting an application. However, see my thoughts at the very top of this comment.
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.
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:
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".
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...
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.
I think hype is just a question of self-control. But you're right, not everyone can remain outside the hype-loop
Including Google themselves. They re-implemented the whole of Youtube with v0 spec which now causes problems in some browsers.
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)
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.
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.
I mean the whole thing started with MS HTC and FF XBL. So the idea of web components goes way back.
I'm genuinely curious what others are using to solve the real world problem of consuming a design system's components in existing applications that are in various tech stacks? Suppose you're building components to be used in Angular, React, Vue, [whatever hot new framework].
Are you using Stencil to build Web Components? Is Svelte viable?
I think a major point is that web components are low level API that are unconcerned about where they live. At least with LitElement based web components that we've built. I can't speak for every method used to create them because I believe lit-element and lit-html were built with the goal of eventually making those libraries unnecessary as more gaps get filled in browser specs.
I'm super curious about this as well.
A few months ago, I worked on a design system project where we faced this question and decided to focus on CSS only, at least to start. We followed Bulma's example and instructed developers to add classes like
is-active
oris-loading
using a framework of their choice. More complicated functionality will probably require web components or something similar - think data tables, date pickers, etc. - but vanilla CSS isn't a bad place to start.Here are some examples of what other design systems are doing:
web componentsCSS and vanilla JavaScript. It just left beta in March. There are Material Design implementations for Java, Swift, Web, Angular, etc.Carbon looks to be experimenting