Use `:host` in selectors to better support web components
Prerequisites
- [X] I have searched for duplicate or closed feature requests
- [X] I have read the contributing guidelines
Proposal
update css variable selector from :root to :root,:host
Motivation and context
I want to use Bootstrap 5.x (currently 5.1.3) with a web component. Unfortunately, all the CSS variables defining color, font, etc are not pulled in because web components do not have a :root. I believe a web component's counterpart to :root is :host (see mdn, here)
I'll also point out I'm absolutely stealing this "fix" from font awesome
If I edit the bootstrap CSS by updating :root { ... } to :root,:host { ... } this corrects the issue.
Is this something that could be updated with Bootstrap to better support web components? I'd be happy to submit a PR.
Thanks for reporting this issue @engenb.
I agree that's probably missing in Bootstrap to work with Web Components. I encountered the same issue while working on this topic and some coworkers as well in our fork of Bootstrap.
At the moment, IDK exactly what would be the impact of changing :root { ... } to :root, :host { ... }. Let's dig it!
If anyone has already any information or leads, please add them in comments :)
I've seen this in other code base and haven't run into any issues thus far. I am curious if we'll need to adapt anything for dark mode, but it's probably fine :).
Here's a sample of the issue with actual :root declaration :
https://jsbin.com/zazedehola/5/edit?html,js,output Collapse is not well displayed due to shadow dom
We need to embed the css inside the component at time : https://jsbin.com/kunonodiro/1/edit?html,js,output
This can be avoid if :host is used and not only :root
for anyone else following along, I'm developing my web components with Vue3 and am able to work around this with the following added to my top-most component. would be great if this wasn't necessary though!
<style lang="scss">
@import 'bootstrap';
:root, :host { @extend :root; }
</style>
I'd like to chime in and say that it's not enough to change :root to :root,:host. It solves the css variables but there are also some styles applied to body { ... } (such as font-family) which won't work in a web component. Not sure what the proper fix for that is though.
I got troubles understanding the issue precisely with my first tests and had a chat with @Lausselloic (thanks for that) to have more details.
If my understanding is right we have 3 use cases:
-
The first one loads
bootstrap.min.cssfile in the main document. So the web component has access to the CSS vars defined in:rootbut doesn't have access to the.accordion*classes. So in terms of rendering, accordions are broken but the div with colors is OK. -
The second one loads
bootstrap.min.cssfile in the main document AND in the web component. So the web component has access to the CSS vars defined in:rootbecause the CSS file is loaded in the main document, and the.accordion*classes work because of the loading of Bootstrap CSS file within the web component. - Finally the third one only loads
bootstrap.min.csswithin the web component; and it seems to be what's this issue is about right? For example, a use case would be that the main document loading Material or whatever, and the web component would use Bootstrap component and style. In this case, indeed, CSS vars defined in:rootare not accessible (the div with colors remains black on white bg) and the accordion style doesn't work fully because it also depends on some CSS vars defined in:root. This is why we need:root, :hostin this case so that these CSS vars are accessible.
Don't hesitate to tell me if this is not correct. While waiting for feedback, I'll continue to work on https://github.com/twbs/bootstrap/pull/37162 with this latest example in mind.
However, as pointed by @mlandalv, it won't fix everything. It's going to be better but not enough. Not sure what would be the proper fix for that.
My two cents: if you're using Bootstrap for your components styles, markup could definitely sit in the Light DOM. That's how Lion delivers white label Web Components, thus allows any styling strategy.
Having custom properties defined on :host will make boostrap work inside a web component but you won't be able to customize the component through those same properties. Those declared in the component could not be ovewritten from "outside".
It could be intended, or not, depending on the kind of component youre are doing. If you don't want your web component to be customizable, it's a good thing. But if you make a webcomponent in order to replace Bootstrap JS, maybe you want to inherit website custom properties values.
EDIT : I played with custom properties and you obviously can override component custom properties from the "outside", they need to be set on the custom element itself (that would be a problem for customizing component if we could not)