Use web components for what they’re good at
nolanlawson.com
nolanlawson.com
If Web Components are so great, why am I not using them? - https://news.ycombinator.com/item?id=36976670 - Aug 2023 (181 comments)
It was this old angular 1.8 app with new features being written in angular-hybrid-ized angular 8. Ripping out angular-hybrid and separating the angular 1.8 routes from the modern angular routes was difficult, but now they were totally separate.
The only thing linking them together was an object with some RXJS streams in it for state, and a little in-house wrapper “app” which just loaded one component or the other with some attributes depending on the URL and a hash of routes for config. (I’d probably use SingleSPA [1] now. Same thing really.)
We could deploy them separately since the build just ends up being another JS file somewhere that just gets included with a script tag at runtime. No version bumping! No big mega build!
We started replacing the remaining “old” routes 1 by 1 with a “new” counter part. That was the easiest part, and went at a pace devs were comfortable with (fast enough) and business folk could tolerate. (modular enough to not HAVE to be done all at once)
Last I checked, the angular 1.8 stuff is gone years ago. :)
I never see them discussed or suggested to solve problems. I see libraries of components/widgets offer versions for React and Vue and other things, never a web component version. No matter how good they may be they seem to have almost no mindshare.
All major browsers appear to have supported autonomous custom elements since ~2019.
That said based on this page this is a nonstarter at my company.
If it doesn’t work easily React, it’s dead. The fact you can’t pass objects or functions would be a huge pain. Of course you can’t pass objects to traditional HTML elements either (outside react) or functions (basically) so I’m not sure why I’m surprised at that. But being able to do that is what makes using React components so easy. Having to add listeners sounds like going back to the battle days of early jquery to me.
Additionally having poor accessibility support in 2023 is also a non-starter. We’re required to provide that in everything we do.
It’s not web components’ fault if React doesn’t fit their model, or browsers have poor accessibility support when web components are involved. But it’s still a blocker.
I can think of a at least one thing we do that being able to ship it as a web component would be very useful for. But we need to be able to pass objects in and out, which I guess would require marshaling and unmarshalling JSON. And that destroys ease of use.
Others have already mentioned the bundler problem.
Unfortunately the tone of this piece kind of reads as “come on, they’re not that bad, really“ instead of the cheerleading piece I was expecting. It had to mention a number of big caveats up front. I’m glad it did to provide an accurate picture. But unfortunately I think it actually reinforced to me the exact feeling they were trying to argue against.
In this regard, because I don't want to be tied to a JS framework (because most of the time I don't even use one) but I still want to have a cohesive set of UI components, I've been using Shoelace: https://shoelace.style
You can use it any way you want, with a framework or not, in a SPA or not. It's a bit like using Bootstrap components, except you get much less markup cruft.
Their own bullet points:
- Works with all frameworks
- Works with CDNs
- Fully customizable with CSS
- Includes a dark theme
- Built with accessibility in mind
- First-class React support
- Built-in localization
- Open source
Also it looks great out of the box.It ships React components that act as adaptors for them out of the box (and has examples with other frameworks as well - see https://github.com/microsoft/vscode-webview-ui-toolkit-sampl...).
Adobe maintains https://github.com/adobe/lit-mobx which is thee current usual way to write https://lit.dev components that use https://mobx.js.org for state management.
So that's two noticeable Enterprise usages even if they don't seem to show up on HN much.
https://custom-elements-everywhere.com/
You can see how React fares for itself.
Per Dan’s comment [1], they began rolling out the flag to test support at Meta in February and, barring any major problems, they’re still targeting 19.
0: https://github.com/facebook/react/issues/11347
1: https://github.com/facebook/react/issues/11347#issuecomment-...
Because that was their design choice: if you write attributes you pass them as attributes to the components
> I personally don’t understand why this hasn’t been fixed.
Because React is very popular and it's used everywhere in Facebook. You can't just change the behaviour without breaing a lot of stuff
> Preact has managed to support properties
> it would be fairly easy for React as well.
Yup, they should "just" do it. Meanwhile, here's an overview of what's needed for that support: https://github.com/facebook/react/issues/11347
Preact uses Option 2 in the list. Other libraries go for either Option 1 or Option 3. React is going with option 2 in an experimental branch.
https://javascript.info/dom-attributes-and-properties
In particular:
> So, if an attribute is non-standard, there won’t be a DOM-property for it. Is there a way to access such attributes?
> Sure. All attributes are accessible by using the following methods:
> elem.hasAttribute(name) – checks for existence.
> elem.getAttribute(name) – gets the value.
> elem.setAttribute(name, value) – sets the value.
> elem.removeAttribute(name) – removes the attribute.
> These methods operate exactly with what’s written in HTML.
First, the idea that one of web components' strengths is bypassing serverside rendering is a bit misleading. SSR has been foundational to reducing time to first meaningful paint, ensuring accessibility, and improving seo. to argue that bypassing it is an advantage seems antithetical to best practices, even when using client-side tech like web components.
Second, the transition example from react to svelte highlights the use of web components as a bridge, but I fear it oversimplifies the reality of such transitions. Its true that web components might provide a superficial level of interoperability, underneath, the application architecture, state management, and data flow can differ vastly between frameworks. Simply plopping an old component with a new one doesn’t mean they’ll play nice without substantial architectural considerations.
Finally, the mention of "no bundler, no transpiler" as an advantage is curious. in practice, the modern web development ecosystem has moved towards using tools like bundlers and transpilers to optimize delivery, reduce overhead, and facilitate modular development. this isn't about complexity, but rather about efficiency and best practices.
Web components certainly have their place and, used judiciously, can certainly add value. It's just essential to approach them with a nuanced understanding and not as a silver bullet.
This comment deserves some clarity.
Web components should not bypass server-side rendering. However, that server-side rendering should not come from the web components themselves. Rather, the "SSR" in this case should be the job of whatever generates the page HTML.
The page HTML should include default "slotted" content (inside the custom element's tag) to be picked up by the web component when the page loads. That's the best way to do progressive enhancement in web component land. Whenever I reach a point when I think, "Gee, I wish I could SSR this web component," I take it as a bad smell, like I'm probably not taking advantage of web component features.
Put another way, I wouldn't want to SSR a web component for the same reason I wouldn't want to SSR a <p> tag. The latter makes no sense, right? Web components are custom elements, and they should be treated like elements, and designed like elements.
> Web components certainly have their place and, used judiciously, can certainly add value. It's just essential to approach them with a nuanced understanding and not as a silver bullet.
Fully agreed with this, it should be repeated over and over. Web components can be part of a balanced diet but they can't be the whole meal.
The author mentioned Lit not having a stable SSR story (a small, fast library to leverage web components).
My suspicion here is that some do too much within their components that they want to render on the server.
There’s two possible solutions already:
1. Don’t generate all your html inside the component (in js), but instead use the component to enclose markup that you render on the server.
2. Decouple html rendering (lit-html) from your component. If your component calls a function that spits out html, so can your server (if it runs JS).
- About bundling, the current reality is that frameworks like React come with a huge amount of dependencies/boat... On the other hand, native Web Components require no dependencies. Web Components will generally load much faster even without bundling than React + all dependencies in a bundle because those bundles are often huge... Not to mention that nowadays, tags expose some nice attribute which let you control the loading and execution order of scripts in a highly fine-grained way (e.g. async and defer attributes on the script tag). That's even without going into the fact that since HTTP2, servers have the ability to preemptively push resources to the client without any round-trip latency. Also, loading resources separately allows for more fine-grained cashing with CDNs; you share some components between some pages and you only need to load what you need explicitly as needed.
Every time I hear someone describe their reasons for using SSR I usually can't figure out why they're building an SPA in the first place.
What I see is that sometimes young front-end developers use their favorite tools (ie. the JS ecosystem) and are unaware of (or have not practiced) the "old way" of building server-side applications and websites.
For example, front-end templating systems are usually come with a lot more than more traditional templating engines. I can get autocomplete on component names and attributes, squigglies when I do something wrong, type safety, as well as more logical import/scoping rules - just follow the import lines and you find where a component was defined. Meanwhile, partials tend to be much more stringly typed, have very little IDE support, and often still seem to use a global partials folder to define reusable components.
The other big thing that I miss in traditional templating engines is scoping for web technologies. Being able to collocate styles and HTML structure is incredibly useful, and makes it a lot easier to share components around in different contexts. Similarly, if I have an accordion partial that uses a bit of Javascript for progressive enhancement, it's very useful to be able to group that Javascript with the partial, scope it to that context, and let the templating engine hook everything up. Scoped CSS (however you implement it, be that CSS modules, CSS-in-JS, tailwind, or whatever else) is a godsend for making really robust components, and I've never found anything even half as good on the server side.
Hey, we were just waiting for the dust to settle, we're catching up now ;)
I know there are a handful of tools that can do this for server rendered templates, but they are very rare and very underutilised, and typically don't have the LSP/IDE support that JSX or single-file-components do.
I do not know any server-side templating languages that do scoped CSS, much less any sort of scoped JS. By that I mean, I can write a CSS declaration (in CSS syntax or otherwise) and guarantee that it will only be used in one place, scoped to a single component (or template partial). This means I'm no longer stuck with the global CSS namespace, and I can link my CSS files directly with the components that use them.
None of the concepts you're talking about are unique to SPA's. A cursory search for "CSS modules rails" or "tailwind django" turned up several pages of results.
Likewise, your cursory search for CSS modules in rails mainly returns blog posts where people try and hack things together to get CSS modules working well enough. The top result for me literally wrote "I tried to find a cool way to integrate CSS Modules into our Rails project, but I cannot", then explains how they parsed CSS by themselves. (I can't get further than that, because Medium.) Meanwhile, adding CSS modules to a project bundled with Vite is literally just a matter of naming your files `.module.css` instead of just `.css`.
Tailwind is a bit of an exception, as it seems to be more popular with backend frameworks, I think because it relies less on Javascript idioms like imports. I suspect we'll see it - or at least similar ideas - integrated into more frameworks over time.
But to me coming from the frontend, this sort of stuff is table-stakes - having IDE support, having Typescript support (and good TS support), being immediately accessible without spending a day fiddling with fifteen different plugins, etc.
Concepts like CSS modules may not be as trendy in server side rendering frameworks, but that doesn't mean the concept itself is inherently limited to SPA's.
Things like IDE support have been table stakes for backend developers working in static languages for a very long time. Javascript tooling is just now finally catching up.
They are, however, inherently limited to Javascript. Because CSS Modules are explicitly a Javascript feature.
Yes, you could do a similar thing in other languages, and people will, but simply by definition those are not CSS Modules, and might diverge from the actual "standard" (which it isn't yet)
Even when building a website, it is exceedingly convenient to compartmentalize large chunks of code into small, manageable UI components that can then be composed together. You will remember the uniquitous "partials" in server-side templating languages/engines/frameworks, such as rails, blade, or nunjucks. Such partials are good for extracting markup; but they do not solve the problem of co-locating the markup with the styles and interactivity associated with it. You can see an attempt to achieve this vision in such projects as Enhance, or webc, or even Astro, whose focus is on building html-first, server-rendered "websites" out of small UI components. But the syntax that these projects use is non-standard and unique to each of the projects. We are in dire need of a web standard way of doing sane server-side templating, which web components could have helped achieve; and my hope is that they will; only right now they still suck at this.
React was designed by Facebook, a website that is mostly behind a login wall and not indexed. The complaint that React is bad for SEO is therefore somewhat ahistorical. Of course you can use React as a templating engine with SSR and it works just fine, but the original value proposition of React was interactivity.
It seems that nowadays the majority of people are using React in non-interactive contexts, which can be a bit weird for those of us who adopted it as a replacement for jQuery, rather than as a replacement for template engines.
finally some sanity
I'd never considered to implement a multi-page website navbar as a front-end component before. For code reuse in a multi-page website, one would typically rely on a server-side pre-processing engine (e.g. PHP, ASP.net, ...) but the pervasiveness and lightweight nature of web-components now makes this a possibility.
Of course you could. Depends on framework, but you certainly could.
It’s like we’re “cashing” in on REST being inherently cache friendly.
> It might also surprise you to learn that, by some measures, React is used on roughly 8% of page loads, whereas web components are used on 20%.
https://mastodon.social/@westbrook/110774427407999573
I suppose it’s because you can probably use web components on top of frameworks.
Then at nytimes.com I found React and this:
Yp = function(a, b) {
var c = window;
var d = void 0 === d ? wb : d;
var e;
if (c.customElements && null != (e = c.Reflect) && e.construct && !c.customElements.get("google-product-ad")) {
Real elegant.After that I checked ask.metafilter.com and saw it has neither.
I fully expect their site to become the same mess as their previous React re-write. I mean, it already is. There are people arguing that 2 seconds to load text and images is fast, actually: https://twitter.com/addyosmani/status/1678117107597471745 ("Engineering Leader, Google Chrome"). And they already load 109 JS files to display it.
The only major problem I noticed is that the "comments" button wasn't a link so you couldn't open it in a new tab. I don't know why web devs hate real links. They think the only think you can do with a link is click it to open the target page.
Of course it’s ad-tech.
Edit: github.com has matches for both "react\b" and "customElements", and I expected that because I've read about Web Components on their blog.
I literally can’t remember the last time I saw a mention of web components online, let alone an article about them.
Which is one of the reasons I was so interested to read this one.
My anecdata differs. There were several articles about them on HN in the last 6 weeks.
> straight JS with no libs or Svelte
Web Components is starting to fit under this.
Nope. Vanishingly few people write web components without libs like lit or Stencil.
https://github.com/github/details-dialog-element
There should be others here:
https://github.com/web-padawan/awesome-web-components#compon...
But then some time passes, and they end up implementing things like new search and code view in React: https://github.blog/2023-06-21-crafting-a-better-faster-code... :)
Even the most loud voices in the web component space almost exclusively advocate lit and stencil for development.
Hence "vanishingly few"
Also IIRC those stats count page views, not pages. So, if you remove Youtube (which Google forced into web components as early as V0) ang Google's ad tech....
https://dev.to/ryansolid/maybe-web-components-are-not-the-fu...
In the meantime, browsers were forging ahead with a lot of nice features that had been planned for a long time and which would make the frameworks redundant and now that these features are available, the frameworks have gained a lot of inertia and it's hard to people to accept that you don't need them anymore due to large scale sunk cost fallacy... Not to mention all the vested interests (platform providers) who built on top of React.
Yes, yes you do. Even with all the nice things there are very few things that are actually useful and usable. Even web components are no longer advertised as "framework replacements", but as "yeah, they are aimed at library and framework authors" (and vanishingly few libraries and frameworks use them due to their many shortcomings)
With many frameworks, I find that most of my debugging work is related to framework-specific gotchas. For example, just this week, I was debugging a VueJS app and it would run validation rules on an input field before it was ready and it caused a flickering red error border around the input box. It was a case where the content of the input field had to be sanitized; that input field needed a second rendering if the user pasted content directly into it (as opposed to typing). It took me a while to come up with a workaround because VueJS controlled the timing of when the validation rule would be enforced (on render) and I couldn't control the timing. I had to create an additional reactive 'isInputReady' variable and use it inside the validation function that I provided to the VueJS input component through the rules attribute... Kind of hacky but there is no friction-less way (without the browser prompting the user) to intercept clipboard data before the content was inserted into the input field; the only way to do sensitization of pasted data was through a re-rendering but I could not stop the red flicker without adding this extra isReady variable and making it part of the validation rule...
Anyway my point is that when using a framework, you run into these types of tricky issues all the time and you have to come up with equally tricky workarounds. I don't run into these issues when using Web Components because I have full control over the rendering. I don't need to make a component reactive for cases where reactivity gets in the way.
Not really. The perceived simplicity of Web Components makes you deal with issues that you should never have to deal with, and reinvent your own libraries and frameworks for even the simplest things, and you will still run into unexpected gotchas.
Especially if your components will be used by others (cross-root ARIA, SSR, styling, proper form participation etc.).
But even for what are not even supposed to be issues. It's a good thing you mentioned an input box. Properly re-rendering an input box in response to certain events or state changes will be either lots of tedious manual work, or running into issues like losing focus, user input, and values. And there's literally nothing in web components to help you with that: use or create your own library to deal with it.
The behaviour you described for Vue is surprising though...
> I don't run into these issues when using Web Components because I have full control over the rendering.
Not really you don't. For example, web components are eagerly rendered, and there's really not much you can do to prevent a rendering cascade when in reality you want something to load and render lazily.
You can't coordinate between various components on the page, so they will all have their own idea of when to render.
Since then they've become the complete antithesis of that vision
People like Nolan really stand out.
Little known fact: adding one line of code turns your Svelte component into a custom element (aka web component).
> This is about as close as you can get to the original vision for web components, which is that using <fancy-element> should be as easy as using built-in HTML elements.
However two things are bad about them:
1. They break the otherwise consistent dynamism of JS. You can’t re-register custom elements. This is incredibly disappointing.
2. The shadow dom is a separate concept lumped together with the rest, which is painful. A typical case of people anticipating specific usage instead of making a modular, simple design.
Yes, yes. Years of trying to cut off the long tail of a migration will make you a bit squeamish.