Anecdotally it feels like they arrived right as headless/self-styled component libraries started to pick up steam, and things inverted to the point that not being able to have your "external" styles easily apply to the component became more of a problem than them being affected by random stray styles.
I wonder if that is the true reason OLE type systems have failed on the web, as there aren’t enough agreed upon preexisting widgets for it not to descend into an inconsistent horror show.
This is the inherent tension. It requires good web component authoring to expose:
1. `part`s that can be accessed by application-level CSS
2. slots for the application developer to inject html
3. CSS custom properties (--variable) -- these pierce the shadow DOM
The web component authors have to be very intentional about these things. There are good examples and bad examples and I think people are still learning how to do this well.
It is almost like the need for styling necessitates all the old dependency injection and factory gunk that older frameworks became notorious for.
.login-form { --button-outline-width: 2px; }
.credit-card-form { --button-outline-width: 2px; }
Of course, the component needs to be authored & documented in a way that supports this.
For example, shoelace has a "Drawer" component: https://shoelace.style/components/drawer
By default the drawer component has an "X" button in the header to close it. If you want to override that, instead of trying to style the nested "X" button you can pass in your own header actions with slot="header-actions"
In practice, this update is great for usability. But it's a sign that web components are still relevant, extending my time dealing with poorly built ones.
More broadly speaking I have found myself getting thrashed by the ever evolving "best practices" in the React ecosystem. First: write everything using class components, and then a couple years later everything should be written with hooks.
I think the benefit of web components (for certain things) is that the APIs and the standards move slowly. Something you write today isn't going to feel obsolete in only a couple years.
If you need an equivalent Expedient Field Hack for a web component, remember it's an HTMLElement subclass and ends up in the DOM. So you can get the object back out of the DOM as 'just another internal element' and gutwrench it from there (or, depending, subclass it and register your subclass, or insert an extra entry into its prototype chain, or ...).
I mean, yes, those are all horrible, but so's digging into the guts of a react component you don't own, sometimes taking a dependency on the internals of somebody else's code is the least horrible option.
... it occurs to me that given a JS Function's .toString() returns the source code, on an e.g. lit-html component you could probably even grab the render function, yank the html`...` call out of it, regexp that to tweak the mark up, and then use an indirect eval to stuff it back in.
But really, I think "you now have the element object, monkey patch it to taste" is probably quite sufficient and far, far less ridiculous than that last paragraph, I just couldn't resist sharing the horrifying thought :)
Yes, ad-hoc fixing styles and behavior from the outside is nice. But when every internal style/class/element is technically part of the API surface, you quickly end up with extremely brittle code.
Suddenly every tiny change (bug fixes, refactors, new feature) in the component library has the potential to break the app in unexpected ways, and the result is an inability to upgrade. Happens all the time.
With shadow DOM, this problem basically go away (depending on how it’s implemented)
Such as what?
The only issue with web components is shadow dom makes styling a pain so you need to work without the shadow dom and implement slots yourself.
Personally I wouldn't mind server rendered features like what react does but in the setting of not javascript.