twbs / bootstrap

The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web.
https://getbootstrap.com
MIT License
169.76k stars 78.71k forks source link

Use `:host` in selectors to better support web components #36688

Open engenb opened 2 years ago

engenb commented 2 years ago

Prerequisites

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.

julien-deramond commented 2 years ago

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 :)

mdo commented 2 years ago

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 :).

Lausselloic commented 2 years ago

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

engenb commented 2 years ago

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>
mlandalv commented 1 year ago

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.

julien-deramond commented 1 year ago

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:

  1. The first one loads bootstrap.min.css file in the main document. So the web component has access to the CSS vars defined in :root but doesn't have access to the .accordion* classes. So in terms of rendering, accordions are broken but the div with colors is OK.
  2. The second one loads bootstrap.min.css file in the main document AND in the web component. So the web component has access to the CSS vars defined in :root because 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.
  3. Finally the third one only loads bootstrap.min.css within 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 :root are 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, :host in 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.

ffoodd commented 1 year ago

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.

vprothais commented 1 year ago

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)