For one thing, I just genuinely think WebComponents are a badly designed API that is weird and hard to use (how many people are using WebComponents without at least Lit, if not something much bigger?), and React is a relatively well-designed library that isn't really that bloated. There's not really much of a point in trying to argue since this is inherently subjective and people with different values are going to irreconcilably disagree. But, if you don't respect that some people hold this position, we're not going to make any progress towards a consensus.
On the note of <dialog>, I recently tried to use <dialog> in a (React) application, and it did work pretty well, but I also found that in Firefox it is only practically possible to do a fade-in animation, not a fade-out one. That isn't really a critical issue for me, it is just an animation after all, but I find it unfortunate. I also find <dialog> to be a weirdly shaped API too: I don't really hate it, but I don't love it either. It feels awkward.
I find this implicit view that developers that, for example, prefer React over WebComponents are making a suboptimal choice to be rather condescending and not really in the spirit of trying to see things from the other side. Wouldn't you want to focus on the strongest arguments and not the weakest ones? Maybe you've literally never heard anyone complain about WebComponents or Shadow DOM, but if so, I find that surprising. Certainly here on HN, I've seen a fair bit of WebComponents hate.
I do, FWIW, realize that I've particularly focused on WebComponents, which this article doesn't actually name directly. But, I assume we're not talking about ditching React to implement our own component framework on top of the traditional DOM APIs, because that's what React already does...
> React is a relatively well-designed library that isn't really that bloated.
I am one of the people who irreconcilably disagree. I think svelte and solidjs are - obviously - technically superior. But it leaves the question of why react is still so popular. I think the biggest reason is all the non-technical aspects of react:
- They have excellent documentation. And have, from day 1.
- They produced videos, sample projects, and all sorts of "getting started" documentation.
- They ran react conferences, teaching everyone who would listen about "1 way data flows" and pretending like they invented FP.
The amount of hype around it made it really feel like the next big thing. Between the very well funded react team and the outside developer community, there was real momentum. People learned it in droves. Taught students. Built websites with it. When react's poor design choices caused issues (and there were a lot of issues), then you were blamed for holding it wrong. (Component classes, state, CSS, hooks, webpack and babel taking ages, big bundle sizes, slow re-renders, and so on.)
By the time the next generation of JS frameworks broke onto the scene, there was a collective moan from the community. "Oh no, not again - we just relearned how to make websites." React was the wave, and in its wake we all had Framework fatigue.
Software doesn't get popular without a lot of work by dedicated people. I really admire the work standards bodies do. But they rarely bother to take the time to produce documentation, videos, tutorials, starter projects, blogs and podcasts and all the rest of that work.
> pretending like they invented FP
More like trying to explain to people who have only done imperative programming (and that also in JS of all languages) why a render function was necessary. The creator of React, Jordan Walke, was big into OCaml and one might even say he got some of the ideas of React through working in OCaml, so much so that he tried to bridge both by making ReasonML which is an alternative syntax for OCaml which has JSX and React bindings.
Yeah, there's a lot of people who have either forgotten or never knew that the context React came into was a world full of JQuery and AngularJS two-way bindings. I started my internet touching career having to work on that stuff, and boy, so much of it was a nightmare that just got endless workarounds heaped on top for basic performance issues, let alone other complications.
There really isn't anything in react that is inherently "bloated", most companies were indeed using it wrong, or at least in a naive way. Over-reliance on useEffects, re-render issues, non-memoized components etc. When used correctly, react 18 provides really fast web apps on whatever scale (small one pager app to massive enterprise apps).
> most companies were indeed using it wrong
If everyone is using react wrong, react has a design flaw. Other frameworks aren't slow by default.
> I am one of the people who irreconcilably disagree. I think svelte and solidjs are - obviously - technically superior.
I don't really think that React is necessarily the best possible library, but there is certainly more to a UI library than simply compiling out the need for diffing. For one thing, I find JSX to be a relatively unobtrusive addition to the language. It is implemented by a variety of things and is a pretty simple transform as far as things go; basically pure sugar, it's possible to avoid it if you want. It could be better designed than it is, but I think it's at least sufficiently general - it is feasible to say, use an alternate library with JSX, like Preact.
Svelte on the other hand by its nature just simply requires a more complicated compiler step to work and deliver on its promises. That's a trade-off. Whether you think it's worth it is up to you, but presenting it as an objectively technically superior design is disingenuous. Superior how? Runtime costs? Sure, but it does beg the question how much. Will a well-optimized Svelte app feel much better than a well-optimized React app?
> The amount of hype around it made it really feel like the next big thing.
We are a really long way away from the hype of React. I would argue that hype stopped carrying React a long time ago. Momentum? Sure, but if something was truly dramatically better, then I think it would have a fair shake at beating out React.
The problem is that the web isn't microbenchmarks and developer experience does matter to some degree, so the trade-offs that seem so good on paper don't always pan out.
I'm not a hater of Svelte. On paper, it is a very elegant idea. However, when I actually tried to use it, I genuinely came out feeling that it was simply not for me, and the benefits it has are not enticing enough for me to continue experimenting. My React apps are not particularly slow or bad at handling huge amounts of data. (One of my apps has no problem handling a file grid of over 1 million items, and in fact, I run into issues with browsers not being able to handle a large enough scroll area long before performance of my React code is a problem. That is good enough for me.)
I should probably be more balanced when criticising react. React moved the state of the art forward when it came out. Compared to the other options we had at the time, it was excellent. But it's not better now. At least not for technical reasons.
> Superior how? Runtime costs? Sure, but it does beg the question how much. Will a well-optimized Svelte app feel much better than a well-optimized React app?
Virtual dom diffing is pure overhead. It increases the JS bundle size (react is big). Vdom diffing is really slow. And it's simply not necessary.
I agree that if you make heavy use of comparator functions, react apps can feel ok to use. But most sites don't do that. Look at the new reddit site. Insanely slow and insanely inefficient. They've improved it a lot since the new design landed. But it's still 19mb of javascript or something, and much slower than it should be. Maybe reddit is only slow because they're holding react wrong. But if everyone holds react wrong, it's react's fault.
If you don't like the asthetics of svelte, check out SolidJS. Solid is aesthetically almost identical to react. Solid - like react - only needs compilation if you're using jsx. The difference between solid and react is that solid only executes component functions once. Reactivity is implemented via fine-grained signals. Solidjs apps perform better, because there's no vdom. The default way to use solid is already fast.
> if something was truly dramatically better, then I think it would have a fair shake at beating out React.
Eh. Lots of old technologies are still in use. Most software engineers don't enjoy learning new frameworks every few years. And react still works fine, even if there are other options today. I think solid and svelte are better, but they might not be better enough to displace react for the average web developer.
If you like react, give solidjs a try. It's essentially "react with signals", which I find to be a significant improvement. You get much smaller JS bundles, better performance and better state management. All while keeping a lot of the best parts of react's design philosophy. It's great.
I mean, prior to React the big Framework at the time was AngularJS 1 - a hellscape of two way data binding.
Talking about one-way data flows was an excellent way to speak to a lot of tortured souls at the time (who had just found out they were going to be forced to migrate their projects to something else anyway due to Google's absolutely insane "we're deprecating this, we'll have a replacement for it at... some point, good luck").
The first time my team uses AngularJS professionally, we spent a month to learn the framework, then the velocity and quality were good. The client reported a funny "bug" that the loading icon didn't show, it turned out the async request was too fast that they couldn't see to loading, a fresh experience for them at the time.
Itâs surprising how bad the API is. Shadow DOM makes just about everything worse. Our frontend org opted out of even using Lit, so we get the raw stupidity of the whole idea.
Style encapsulation? You get that, but not fully, and good luck finding out which parts you donât get.
State management? Back to query selectors, which btw work worse and need workarounds when reaching into the shadows.
Slots? After coming from a modern framework, slots are a clear step backwards. In React you can pass a component as a prop but in the shadow DOM world, you have to signify it with HTML. Multiply it by several slots and you get a lot of verbosity just to match the behavior.
Yet to mention using the platform directly means losing so much work around static verifiability. No one has to talk about this anymore, but sticking religiously to the platform by strictly using addEventListener means you canât require event handlers to exist for any of your elements. People forget this, but the browserâs default way of letting you do anything is an enormous footgun for reliability.
Learn from our frontend orgâs mistakes. Run, donât walk, away from it.
> I just genuinely think WebComponents are a badly designed API that is weird and hard to use
This was exactly what sprang to mind as soon as I saw the title. Iâve been writing front-end code for over 25 years now, and exactly two things in that entire time have made me miserable enough to think about stopping: Internet Explorer 6 and web components. Every time I try to just âuse the platformâ it makes me miserable and I end up demotivated and stop working on whatever side project I chose to try again with. And I otherwise like the web platform! Iâve been building with it since there was nothing but the web platform. But web components kill my enthusiasm for it stone dead.
Even now in the age of agentic development, AI trips over all the same footguns in web components that humans do. It just seems like everybody involved has been adding to the standards with âyes, andâŚâ without ever thinking about how it will be used by web developers in practice.
What do you not like about WebComponents?
Say we want to make an icon that when clicked shows how often it was clicked. The webcomponent code seens quite sane to me:
class HelloIcon extends HTMLElement {
connectedCallback() {
this.clickCount = 0;
this.innerHTML = `
<button class="icon">:)</button>
<dialog>
<p>Hello, I was clicked 0 times</p>
<button class="close">Close</button>
</dialog>
`;
const icon = this.querySelector('.icon');
const dialog = this.querySelector('dialog');
const closeBtn = this.querySelector('.close');
const dialogText = this.querySelector('p');
icon.addEventListener('click', () => {
this.clickCount++;
dialogText.textContent = `Hello, I was clicked ${this.clickCount} times`;
dialog.showModal();
});
closeBtn.addEventListener('click', () => dialog.close());
}
}
Try it here:https://plnkr.co/edit/0XUOLyM52xfFiIBu?open=index.html&previ...
I don't know if that's idiomatic webcomponent or not but that looks unmaintainable, even for such a minimal component, imagine once it grows. It's not separating presentation from state and logic. querySelector need to match classes and elements in the markdown. Mutating textContent is going to run out of sync as soon as you have more than one event source doing the same. Those are all problems that React solve by separating state and only rendering in one path.
That's the best case scenario and already looks like crap. If that looks sane to you, I don't know what to say.
Make it have an initial count via attributes, sync it with the DOM so if the attribute changes the count resets, and make the JS property always match the attribute (and vice-versa) so it behaves sanely. You're in for a world of pain even for something as simple as this.
Plus they're not declarative: you will only make me use innerText-based updates by threatening me and my family.
Plus they only work with JS enabled, while I can use JSX in SSR.
I've worked extensively with Web Components. They suck.
This is a very simple component, and its already a mess.
Something with more HTML and javascript is going to be a nightmare.
Then theres the problem of sharing state, the world is far more complicated than something simple in isolation.
Well for one thing, I don't find that to be particularly succinct or nice example. There's a lot going on there:
- HTML in a string. No syntax checks. If you interpolate it, you have to escape manually or you could create trivial XSS vulnerabilities. Your editor will probably not syntax highlight it, making it harder to tell when you break it.
- Manually formatted update logic that is redundant with the string. Not so bad here, but try formulating a practical large component.
- Completely ad-hoc state management, no reconciliation. Again, fine for Hello World, not fine after that.
Using raw WebComponents, your application has to care about all of this on its own and more. You can use templates and slots (which you should) but that makes this even messier IMO and brings back the split that React became famous for getting rid of. We left manual DOM reconciliation, ad-hoc data flow and non-reactive components that manually call a render routine at arbitrary points for a reason: it sucked. It made for buggier, harder to maintain code. It can be done, but usually any decent app will wind up encapsulating patterns into utilities that get reused. And... That's precisely why we want a good library. That's what I want, a library that packages up good reusable patterns for constructing UIs effectively.
And that's exactly my point, which is WebComponents or not, the solution is still basically the same, use libraries. Which begs the question: if I have to use Lit, what is the point of "using the platform"? What is WebComponents doing for me here that React wouldn't be? And in my case, I struggle to see it.
Interoperability? The old way of embedding external components works quite fine. Switching APIs where you pass a DOM node for something to mount into and get back an object with an API to one where you instantiate a component and communicate via properties and events feels like a strictly lateral move. I can't think of a condition where this would be particularly more convenient, but I can think of some where it is actually less. Next.
Isolation? Yes, WebComponents does add tools to provide better isolation between components. For some use cases this is a genuinely useful feature, although it also isn't without tradeoffs (I mean, the flexibility of having things be not isolated comes in clutch sometimes, it's hard to argue this.) But I use React primarily to construct components in an application, where I find this property more undesirable than desirable.
The one thing I thought could be cool with WebComponents is if you could build them in pure HTML when you only needed basic templating, but no: the design they went with always requires subclassing in JS AFAIK.
I could go on and get more specific, but I feel like people will pick everything I just said apart quite enough. I hope I'm at least able to make the case that:
- I do in fact, get the general gist of WebComponents.
- I still don't like it despite that.
> Isolation? Yes, WebComponents does add tools to provide better isolation between components. For some use cases this is a genuinely useful feature, although it also isn't without tradeoffs
I hate the guts of every site that uses those. Shadow DOM makes the site hard to operate and fix programmatically from user end.
I mean, these days I can just throw an LLM at it so I don't care as much, but sometimes I want to still do things hands-on. Not to mention, Shadow DOM is often a difference between "simple userstyle/userscript that is allowed at work by security extensions" vs "requiring things that are banned on corporate-managed browser".
> If you interpolate it, you have to escape manually
Well, for some definition of "manually".
If you have untrusted variables to interpolate, you can do
this.innerHTML = html`Hello ${name}!`
Where html is a function that escapes the variables.The arguments brought forward against web components all seem to fall under "But it does not contain every functionality you want to use out of the box". Personally, I don't think browsers should provide more and more functionality, but rather a good base to build upon.
Coming from a more general programming view, I find web development extremely odd. In general programming we tend to find a small set of abstractions which we can use in a composable way to cover our problem space.
For example, to interact with the VFS, we have read()/write(). When we add more APIs, it can be to enable a new paradigm, like epoll(), or for performance, like readv()/writev(). For a functionality that can be composed out of existing APIs in a performant way, we do not add it in the platform, but leave it instead to the domain of libraries. This separation has immense values, as it makes platforms easy to implement. A Linux filesystem, for example, needs to implement only 10 or so functions.
The web seems to be perfectly composable too, out of <div>, <span>, <p> and a small subset of CSS, but doing this is considered an anti-pattern, and you're supposed to reach for the platform to find the closest thing to what you need, whereas reaching for a library or composing yourself is frowned upon.
The result is that there are only three platforms: Blink/V8; WebKit/JavaScriptCore; and Geko/SpiderMonkey. With many things only working or working well on Blink/V8.
And implementing a new platform is a titanic task.
> there are only three platforms: Blink/V8; WebKit/JavaScriptCore; and Geko/SpiderMonkey.
Youâre misunderstanding the terminology here. The platform being talked about is the World-Wide Web and you are listing three implementations of the client part of the platform.
> The web seems to be perfectly composable too, out of <div>, <span>, <p> and a small subset of CSS, but doing this is considered an anti-pattern, and you're supposed to reach for the platform to find the closest thing to what you need, whereas reaching for a library or composing yourself is frowned upon.
The web has a gazillion libraries...
As far as I know there are still some things "the platform" actually won't deliver; for instance I'm fairly certain there's no searchable combobox that's fully accessible. One ~must leave the platform to give users the experience the expect.
That means "the platform" itself is actually teaching people to work "off platform" and arguably will always have gaps as functionality and expectations evolve.
Admittedly, the habit really ought to be 'I need to make a combobox -> does the platform have what I need? -> Research, evaluate, test -> Otherwise, make it' but I don't begrudge people for skipping the middle steps.
Especially because the last step is less "make it" and more like "npm add it".
The browser has "ready-made components". React (et al) also has "ready-made components". React's selection is a thousand times larger. React also allows you to make your own. The browser doesn't [1].
Who can blame developers for skipping the inconvenient half-solution and going straight to the all-encompassing ecosystem
[1]: It does, but web components are too unwieldy to compete with React
The vast majority of the patterns in the ARIA APG require bespoke JS plumbing for proper focus management, keyboard controls, and etc.
Isnât datalist doing that? Last time I had to build a combo search box I was pleasantly surprised to learn about it
The main reason is flexibility.
One day your boss stands next to you and asks: "can you move this border three pixels to the left", and the only correct answer is "but that requires a complete rewrite".
I think this is completely wrong. The reason why nkt a lot of people use the built in elements is because sooner or later you will hit a limitation that you cannot fix. If it is a javascript element you can do whatever you want if it doesn'fit.
Take dialog as an example. If you have a server side rendered app and you want to show an open dialog without js. You are out of luck, you can't just render it as open because that opens a dialog that does not correctly work. Or take a multiselect input. Just unusable as a normal browser element. Also most elements miss something essential like no search function in an input. So also unusable for big lists. I could make a list of 100 things that are wrong with native browser elements. It is just easier to use a js framework/library and have a clean view and state.
> because sooner or later you will hit a limitation that you cannot fix. If it is a javascript element you can do whatever you want if it doesn'fit.
This is a crutch that people lean on to not use the right thing and use what theyâre familiar with. Start with the browser default and change when it doesnât work in that case.
> It is just easier to use a js framework/library and have a clean view and state.
To note, it's "easier" if you don't really care outside of your specific and limited case.
Multi select is a perfect example: if you only ever need that component to work in your language on your specific list for the browser you personally use for the screen sizes you care about, it will be pretty easy.
Hell starts when you try to think beyond that: how does the JS component work in responsive for super small screens and super big screens ? do you handle touch and mouse and stuff in-between ? what about CJK ? Right to Left ? do you care if there is any very long entries in the list ? How do you handle previous selections ?
The more you start to care about the details or expand the range of what you're doing, the more you'll be pulling hairs if you try to handle them.
The native components won't be perfect either. Native devs will also be dwelling in that same hell as you, whether or not the native state is better will depend on how much they cared on their side.
This issue remains true even with the JS "wrapper" elements.
The number of times I have senen frontend people pull in some frontend component from a library (say, for fancy select widgets) and then have to spend a bunch of time trying to fight the existing bugs in that... and then struggle to swap it out later on for another library with a distinct set of bugs...
UI is hard, so it's hard to have a general thing fit _your_ specific purposes nicely. This is why I think it's super valuable to wrap things you can't control easily. That way you both document what you _do_ use, can fix issues at a bit of a higher level, and can swap out the internals way more easily.
People fight back on me on this on so many projects (the most recent thing: "the LLM won't know about our special UI component" IT WILL! IT CAN READ THE CODE!), but then hit those moments of regrets and end up wrapping stuff anyways.
Especially annoying coming from people who talk about design systems. A base vocabulary is a real good way of enforcing a design system!
I mean this relatively lightly, I understand the qualms at a high level, and coming up with the right abstraction is a skill. I've just felt the burn too many times and have very little issue coming up with very limited abstractractions and relying on tech debt to get my wrapper components out into the world.
I agree. Still better than the native elements. The biggest downside is 100kb js elements because they try to handle everything. I used basecoat and that worked ok, even if some essentials are missing. Currently I am using my own webcomponents created with rocket (from datastar)
I disagree itâs better than the native elements. At least the native elements work reliably rather than just on whatever version of chrome the custom one happened to be tested on
When a technology becomes popular enough, it develops a community that solidifies that choice: conferences, books, extensions, a generation of engineers that see things in terms of React.
A technology needs to be a lot better to overcome that aspect.
Sometimes I visit a subreddit for a tech and see them all discussing strategies/techniques that are ultimately workarounds for what an alternative technology has fundamentally solved, but... the original tech has an army of volunteers able to help newbies workaround it, which is often an easier onboard experience than the alternative tech that just works, but doesn't have any advocating solutions/blog posts because there are no blog posts to be written.
Counterpoint: the problem was solved by an alternative, but was it solved without any tradeoffs? If the solution comes with no real tradeoffs, then that begs the question why React wouldn't simply adopt the solution... And I think this is not a theoretical nitpick, either: Angular actually has, to my knowledge, basically done this more than once. And React certainly doesn't seem afraid to make big or breaking changes, from fibers to suspense to hooks to context, so I don't think it is resistance to change at play here.
I think when you consider that the solutions sometimes may come with tradeoffs that cause problems that people like less than simply working around the first problem, it makes a lot more sense.
I don't think conferences, hype, corporate backing explain the continued success of React; they help but it's just not the full story. I don't think they explain the continued success of anything else, either; I find this to be a shallow and lazy dismissal in most cases. It's easy enough to find counter examples where none of these things, not conferences, hype, corporate backing, or whatever else you could think of, were enough to make something work. While these things definitely help keep something relevant, they can't do it alone.
In fact, in attempting to rationalize the success of React without acknowledging its strengths, I believe people have fundamentally reversed cause and effect. I think a lot of the continued success of React comes from people continuing to choose its set of tradeoffs over others even when they could tolerate risk. I think that conferences continue to be organized and books continue to be written because of its continued success.
The tech community on the Internet has largely matured enough to acknowledge why PHP was and is successful; yes, there are many objective issues with it even today, but it also has many strengths beyond just having existed for a long time, too. Do I think you should choose PHP for new projects, the way I might say for React? Well, no, not really, if I'm being honest. But, I think it was nice to see people grow up and acknowledge that actually, there were and are a lot of redeeming qualities to PHP, and what it did for a lot of people was pretty cool, fractals of bad design be damned. It'd be a shame to see this repeated again more for stuff like React and say, Go, just because it's not the dog in the race we wanted to see win. (And I would understand that position, because I fully understand why people like Svelte, or Rust. I just don't think there is a conspiracy, it's just that there isn't a free lunch here.)
I think we agree, though I can see why it might not have seemed that way, since I didn't draw attention that users might rightly conclude the overall tradeoff is worth it, even if another tech is sounder in some minor aspect.
React can adapt, and though Web Components might still have some claim on X, Y, Z, React still is heavily preferred because all the other things are so much more important to developers.
For what genuine gaps remain, there's lots of React users that can help others through it.
I feel like itâs a historical accident. In the past the platform couldnât do it all, and if you wanted a dialog you had to use a library. Developers were trained to reach for libraries when they needed something like a dialog.
Then react came along and all developed learning web development after react had little to no knowledge of the platform. They were taught that touching the DOM was a bad thing to do.
Thatâs about it. Even now when I advocate for vanilla css I get the side eye and âtailwind and shadcn should be the defaultâ. I get it, itâs what most people are familiar with, even if itâs worse than the platform.
How is tailwind and shadcn worse than platform? It speeds up development by orders of magnitude.
Depends on the criteria, e.g. if dev speed has highest prio, a full blown component lib like Material UI would be superior to shadcn. CSS can obviously do things that tailwind can't, so it is more powerful.
The point of shadcn is you can pull in a component and modify it any way you want. It's always going to be bare bones at the start. Something like MUI locks you into a layout and style that's coupled with the API, and you need to rewrite big chunks of your app if you want to add your own branding.
For me the best middle ground is Headless UI or Bits for Svelte, unstyled and composable but you don't need to vendor code into your repo like shadcn.
Personally, and this is more of a general coding thing than specific to web development, I find a number of imported items are easy to code and write myself, and thus I have control over debugging rather than submitting myself to the process of reporting a bug then hoping it will be fixed in a timely manner. I also have feature control and can avoid feature bloat, and I have full knowledge of the code I am running.
This allows me to speed up development and have a streamlined custom implementation of that feature for my code. For example, I was unhappy recently with performance and feature set in RRDTool. Seeing that updates from the dev for that are quite glacial I wrote my own implementation, which took about 20 minutes, and now I have one less import, and in the process speeded up data retrieval, so I can have 60fps graph generation, discarded unused features, and added a couple of custom ones for my application.
Get a daily email with the the top stories from Hacker News. No spam, unsubscribe at any time.