See the entire conversation

Great questions about Web Components! Here's my response to each question and a few others that were asked in the comments: Q1. Is JS a dependency? A: Web Components are just like any other HTML element. While they can be rendered without JS, it is required for interaction. πŸ‘‡
I just created a draft for a blog post titled “WebComponents FAQ” because I don't know much about 'em. They sound like a great idea, but the pro & contra discussions on Twitter make my brain hurt. I'll use this post to answer my on questions. If you want to add questions, reply!
64 replies and sub-replies as of Jul 09 2022

Q2: What does using Web Components mean for accessibility? A: As I said, Web Components are like any other HTML element so making them accessible is no different from making any other HTML element accessible. Think focus, keyboard interaction, aria attributes πŸ‘‡
Q3: Can I use external CSS? A: Yes, you can. You can add a <link rel=stylesheet> tag to a Web Component or use Constructable Stylesheets. Constructable Stylesheets are available since Chrome 73, Edge 79, Firefox 101, and Opera 53 web.dev/constructable-… πŸ‘‡
Q5: Do I need a third-party library to use Web Components today? A: No, you don't. Web Components are supported in all browsers now. Some experimental features may require a polyfill but the core features are now available everywhere. πŸ‘‡
Q6: What's lit? A: lit is a lightweight library to build Web Components. It provides declarative templates and reactivity. At its core, it's a base class that provides all these features and that you can extend to build Web Components. πŸ‘‡
Q6: What's stenciljs? A: Stenciljs is a build tool that generates Web Components. It also provides declarative templates and reactivity so it's comparable to lit. πŸ‘‡
Q7: Does React support Web Components? A: Yes, but you will probably need to write a wrapper for your Web Component. Out of all JS frameworks, React is not the easiest to integrate Web Components into. πŸ‘‡
Web Components – React
A JavaScript library for building user interfaces
reactjs.org
Q8: Can I use 11ty to compile Web Components to HTML? A: Web Components ARE HTML so there is nothing to compile to HTML. It is already HTML. Web Components are just custom HTML elements that can be used in any HTML page. πŸ‘‡
Q9: What's declarative Shadow DOM? A: Declarative Shadow DOM is the way to add Shadow DOM to a Web Component without JS. It enables server-side rendering of Web Components. πŸ‘‡ web.dev/declarative-sh…
Q10: What are the most important pros? A: Web Components are just standard HTML elements that can be used anywhere and can be integrated into any framework. While frameworks come and go, Web Components are a standard that is unlikely to ever be deprecated. πŸ‘‡
Another very important pro is that you can fully encapsulate the HTML and CSS of your component so you have truly scoped CSS. This enables you to drastically simplify the CSS of your component since it is truly scoped, no convention needed. πŸ‘‡
Q11: What are the most important cons? A: Web Components don't provide features out of the box like data binding and declarative templates that frameworks do (although it's not hard to implement these) πŸ‘‡
Other questions: Q: Can you SSR them? A: Yes, with declarative Shadow DOM. This is not yet supported in Safari. πŸ‘‡
Q: Can you make Web Components reactive? A: Yes, but reactivity is not provided out of the box like in most frameworks. Although it's not hard to implement: πŸ‘‡
Data binding for Web Components in just a few lines of code
It’s not rocket science and Virtual DOM is usually overkill anyway.
medium.com
Q: Is it always smart to use Shadow DOM? A: It really depends on your use case, but usually Shadow DOM will be a good fit since by definition a Web Component is a self-contained unit that will benefit from the encapsulation of HTML and CSS. πŸ‘‡
Q: Why would you choose Web Component over frameworks? A: You can always combine them so you don't have to choose but the benefits of Web Components are that they are standard, can be used anywhere (they're just HTML elements) and provide truly scoped CSS πŸ‘‡
Q: Do Web Component work when JavaScript is disabled? A: They can be rendered with declarative Shadow DOM but for interaction, JS will be needed, just like with components built with other frameworks or any other HTML element.
Oh my! You really just captured how I think about state for WC: having a this.state property. I arrived at the same conclusion a while ago and just love that all things data and mutations are kept to a sub-property of the element, as agains littering the element object itself.
The idea of branching to a sub-property for state also eliminates possible colliosns with existing instance properties of the element. ❌ this.style = 'dark'; βœ… this.state.style = 'dark'; It would be a great win for WC to get "state" standardised!
I did put up a draft proposal for a standard "element.state" and "document.state" property which works with an Observer API to deliver reactivity! Take a look github.com/webqit/oohtml#… (An iteration of this proposal is underway!) The state API is just how I like it!
GitHub - webqit/oohtml: Object-Oriented HTML - a WICG proposal
Object-Oriented HTML - a WICG proposal. Contribute to webqit/oohtml development by creating an account on GitHub.
github.com
I care about reactivity beyond Web Components, and the State API plus the Observer API satisfies just that! And heck, there's a way to unlock reactivity for JavaScript itself as a language! You want to meet the Subscript Functions Proposal:
GitHub - webqit/subscript: A proposed new function primitive that provides a reactive programming context within JavaScript.
A proposed new function primitive that provides a reactive programming context within JavaScript. - GitHub - webqit/subscript: A proposed new function primitive that provides a reactive programming...
github.com
Now, something happens with a coming together of the State API, the Observer API, and Subscript Functions: language-level reactivity! Y'd practically be able do this: class countElement { // A Subscript funtion... **render() { this.innerHTML = this.state.count; } } ...
class countElement { connectedCallback() { this.state.count = 0; this.state.render(); setTimeout(() => this.state.count ++, 1000); } } customElements.define('count-element', countElement); (More in the docs: github.com/webqit/oohtml#… )
GitHub - webqit/oohtml: Object-Oriented HTML - a WICG proposal
Object-Oriented HTML - a WICG proposal. Contribute to webqit/oohtml development by creating an account on GitHub.
github.com
Why is SSR never mentioned as a downside? Am I missing something here? DSD always get mentioned, but what about this ?
how do you turn export default function App() { return <html> ... <my-wc/> </html> } into <html> ... <my-wc> <template shadowroot="open"> <span>some shadow DOM</span> </template> </my-wc> </html> ?
Also, inputs in the Shadow DOM are a pain. Autofill doesn't work. And a simple form requires some additional effort.
Did you know that the shadow dom on #webcomponents containing form elements causes (un)expected behaviour? Due to the input values being encapsulated from the main DOM, the inputs won't be picked up by the form. Some interesting links on how to solve belowπŸ‘‡πŸ»
Yet, you can server-render or pre-render web components to declarative shadow DOM.
If you use SCSS, because it’s your workflow, you absolutely can with Shadow DOM, go wild. We leverage postCSS in most of my projects, and while we need it less and less, not worth pretending we don’t or that others shouldn’t, even if you can skip it in a lot of cases.
i use scss in my build steps also. for components with attrs/props with lots of values scss looping can be really useful
Doesn't <link> in the <body> cause render jank?
I recently started exploring Web components, Can you please share a demo or documentation where web components nested using slot inside another web component is styled from outside like via a global style sheet ?
Something to be aware of though is that shadow boundaries can be difficult to deal with with regards to elements that are referencing each other through ids and aria attributes, form participation doesn't work through them either, there are ways to work around it though
These are great points. Accessibility tends to be a bit harder with WCs because of this boundary, but with awareness it definitely isn’t an impossible goal. Also waiting for ElementInternals to land like
Yess, accessibility object model (AOM) too. It's a positive thing that we can work around the problems AND that there are specs in the work that will solve things properly. Speaking of the workaround, I tend to use slots to project my elements to LightDOM when I need to.
This way I can still style them with ::slotted from my component, so at least those styles dont leak outward, and even though slottables are usually component consumer territory, it's an acceptable temp solution imo.
Yes! I took a different approach with @shoelace_style in that I’m using the formdata event and keeping inputs in the shadow DOM. Have you had trouble using ::slotted? My problem with it is the ridiculously low specificity. Are you using !important a lot?
Omg yes. I use !important for literally every CSS decl that my comp relies on, I am forced to :( because slotted is only the specificity of the pseudo, not of its argument.
Another thing that's annoying is that you can't use ::slotted to style non-tree-abiding pseudos like the input range track and thumb.. so you end up needing some kind of style scope emulation solution, which really is too bad.
I understand your point but in my opinion it makes sense. As a consumer of a web component I would expect any elements I add as slots not to be altered in terms of styling and would be confused if that would happen.
It's an element that is shared between the component author and consumer. The author shapes the slot and the consumer picks what they put in. I think 0,1,0 would make more sense for ::slotted if anything, still easy to override consciously, doesn't constantly happen by accident.
What exactly are the issues you run into?
But maybe, for backwards compatibility, we could introduce something like !default to boost specificity to a more reasonable initial value. Still not great, but better than abusing !important and requiring consumers to use it as well.
Styles that effect elements outside of a shadow root _should_ be no higher than user agent styles & like user agent style they _should_ use !important if they should take priority over user styles. An annoyance but the “right” thing IMO. Hard to see it changing, esp. post @layer.
Technically speaking :host also targets the element outside the shadow, and that one takes the specificity of a pseudo plus that of its argument. I always viewed ::slotted and :host as similar exceptions for the shadow style encapsulation but their specificities are different.
!important has indeed been aegued as the right solution but it still feels like an awfully big hammer for a small nail.
Another path would be great! I’m interested in ways that import assertions can be combined with an external CSS export for a custom element to make more nuanced solutions here possible.
:host IS an element while ::slotted() is the possibility of an element. They deserve to be different. BUT they also deserve to be more powerful. If CSS is performant enough to support Container Queries and :has() et al, then we should be able to do more here!!!
Typically you’re not comparing a wc-button with other HTML elements like input or anchor, you’d compare it to implementing your button by using `button` in a UI library Which is more accessible by default, `button` or `wc-button`?
I knew you would deliver πŸ‘
Thanks David! I hope it was helpful.
Loved this thread! Thanks for sharing Just to clarify the first Q/A, to render a WC (that has no interactivity) without JS you would need to use declarative shadow DOM right?
That is one way, until we get declarative CEs. Another way is to slot children into it and use backup styles with my-el:not(:defined) {...}
Hey Danny, I don’t understand that point. In my experience, I need a ‚registerElement‘ call to declare my element to the browser. How do I do that without JavaScript? Or do you speak about declarative shadow Dom? (But wouldn’t that need registration also?)
Yes declarative Shadow DOM. This enables you to declaratively add a Shadom Root to an element without JS. That part doesn’t need registration.
Nice thread! πŸ‘ Can you please tell me if is it possible to create an alignment container, that accepts any tag as children? <flex-c justify="center"> <div></div> </flex-c>
That should be possible, but why would you use a web component for that?
It was just an example πŸ˜… A PoC for css-in-js not production material The thing here is I have never found a way to load that child element Google was no help
How do you mean “load the child element”? Is it a slot!
Thank you! Now I know the problem is my mental model of web components
Most important con: Native SSR support