I find that they can work very well with state but since state is typically passed via attributes (downstream), it means that components can only share state with each other via strings. I found this to be an advantage, not a drawback because simple interfaces are at the core of my coding philosophy and strings make it infeasible to pass complex instances or functions to other components.
Well, this is only sort of true. When you’re writing HTML you’re restricted to attributes but custom elements are JavaScript objects and are free to respond to property updates on the object. Relying solely on strings is a limitation of your templating engine.
For example lit-html templates support syntax like:
Interesting. I recognize that lit-html is much more lightweight than React and others but personally I really like to avoid any magic at all and I like being forced to pass strings between components. It reminds me of an Alan Kay quote about OOP "The big idea is messaging". You want your components to be passing around messages, not state. This seems to go against FP philosophy but I've found that it really works for OOP. After all, OOP is traditionally about state encapsulation and prioritizing concern boundaries over logic/state boundaries as in FP.
Note that it's still possible to pass complex objects to native we components but only imperatively via properties so it's a lot higher friction (as it should be).