[SOLVED] Import only the Tooltip component/directive with scoped CSS
See original GitHub issueFirst of all, congrats to everyone involved in this project, it’s awesome.
I see the library supports importing only the desired components/directives. By that I mean it’s officially supported to import just the v-b-tooltip
directive (https://bootstrap-vue.js.org/docs/components/tooltip/#importing-individual-directives):
import { VBTooltip } from 'bootstrap-vue'
// Note: Vue automatically prefixes the directive name with 'v-'
Vue.directive('b-tooltip', VBTooltip)
Of course, for this to work you also need CSS:
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
But it’s overkill to import the entire bootstrap AND bootstrap-vue CSS files just for tooltips to work. Also, even if that was not an issue, importing CSS like that means it will pollute the global space. So I tried using scoped styles in my component:
<style scoped src="bootstrap/dist/css/bootstrap.css" />
<style scoped src="bootstrap-vue/dist/bootstrap-vue.css" />
For this to work with the Tooltip, you have to pass an element
for it to mount to, because otherwise it will be mounted on body
, which will be outside the scope of the component.
But even if doing so, I get a broken tooltip like this (note the white text on the right, that’s the tooltip):
Debugging this further, I noticed that even tough my page is loading the correct styles AND it’s scoping them, the tooltip element in itself doesn’t have the data-*
attribute to make it work with the scoped CSS… (note the outer element has the data-
attribute, but the tooltip div doesn’t):
So, this is the CSS being included in the page (note it’s scoped):
.tooltip[data-v-c2ed4f50] {
position: absolute;
z-index: 1070;
display: block;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-style: normal;
font-weight: 400;
line-height: 1.5;
text-align: left;
text-align: start;
text-decoration: none;
text-shadow: none;
text-transform: none;
letter-spacing: normal;
word-break: normal;
word-spacing: normal;
white-space: normal;
line-break: auto;
font-size: 14px;
font-size: 0.875rem;
word-wrap: break-word;
opacity: 0;
}
.tooltip.show[data-v-c2ed4f50] {
opacity: 0.9;
}
.tooltip .arrow[data-v-c2ed4f50] {
position: absolute;
display: block;
width: 12.8px;
width: 0.8rem;
height: 6.4px;
height: 0.4rem;
}
.tooltip .arrow[data-v-c2ed4f50]::before {
position: absolute;
content: "";
border-color: transparent;
border-style: solid;
}
.bs-tooltip-top[data-v-c2ed4f50], .bs-tooltip-auto[x-placement^="top"][data-v-c2ed4f50] {
padding: 6.4px 0;
padding: 0.4rem 0;
}
.bs-tooltip-top .arrow[data-v-c2ed4f50], .bs-tooltip-auto[x-placement^="top"] .arrow[data-v-c2ed4f50] {
bottom: 0;
}
.bs-tooltip-top .arrow[data-v-c2ed4f50]::before, .bs-tooltip-auto[x-placement^="top"] .arrow[data-v-c2ed4f50]::before {
top: 0;
border-width: 6.4px 6.4px 0;
border-width: 0.4rem 0.4rem 0;
border-top-color: #000;
}
.bs-tooltip-right[data-v-c2ed4f50], .bs-tooltip-auto[x-placement^="right"][data-v-c2ed4f50] {
padding: 0 6.4px;
padding: 0 0.4rem;
}
.bs-tooltip-right .arrow[data-v-c2ed4f50], .bs-tooltip-auto[x-placement^="right"] .arrow[data-v-c2ed4f50] {
left: 0;
width: 6.4px;
width: 0.4rem;
height: 12.8px;
height: 0.8rem;
}
.bs-tooltip-right .arrow[data-v-c2ed4f50]::before, .bs-tooltip-auto[x-placement^="right"] .arrow[data-v-c2ed4f50]::before {
right: 0;
border-width: 6.4px 6.4px 6.4px 0;
border-width: 0.4rem 0.4rem 0.4rem 0;
border-right-color: #000;
}
.bs-tooltip-bottom[data-v-c2ed4f50], .bs-tooltip-auto[x-placement^="bottom"][data-v-c2ed4f50] {
padding: 6.4px 0;
padding: 0.4rem 0;
}
.bs-tooltip-bottom .arrow[data-v-c2ed4f50], .bs-tooltip-auto[x-placement^="bottom"] .arrow[data-v-c2ed4f50] {
top: 0;
}
.bs-tooltip-bottom .arrow[data-v-c2ed4f50]::before, .bs-tooltip-auto[x-placement^="bottom"] .arrow[data-v-c2ed4f50]::before {
bottom: 0;
border-width: 0 6.4px 6.4px;
border-width: 0 0.4rem 0.4rem;
border-bottom-color: #000;
}
.bs-tooltip-left[data-v-c2ed4f50], .bs-tooltip-auto[x-placement^="left"][data-v-c2ed4f50] {
padding: 0 6.4px;
padding: 0 0.4rem;
}
.bs-tooltip-left .arrow[data-v-c2ed4f50], .bs-tooltip-auto[x-placement^="left"] .arrow[data-v-c2ed4f50] {
right: 0;
width: 6.4px;
width: 0.4rem;
height: 12.8px;
height: 0.8rem;
}
.bs-tooltip-left .arrow[data-v-c2ed4f50]::before, .bs-tooltip-auto[x-placement^="left"] .arrow[data-v-c2ed4f50]::before {
left: 0;
border-width: 6.4px 0 6.4px 6.4px;
border-width: 0.4rem 0 0.4rem 0.4rem;
border-left-color: #000;
}
.tooltip-inner[data-v-c2ed4f50] {
max-width: 200px;
padding: 4px 8px;
padding: 0.25rem 0.5rem;
color: #fff;
text-align: center;
background-color: #000;
border-radius: 0.25rem;
}
```
But the dom elements of the tooltip itself, as you saw before, even if specifically targeting an mount element inside the component (and not `body`), lack the `data-*` attribute to make them a target for the scoped css.
It would be nice if this could work out of the box. If the library already has support for importing individual components or directives, it would be great if we could load only the necessary CSS for those components, AND even better if that worked with the scoped CSS so it doesn't pollute the global CSS namespace.
Issue Analytics
- State:
- Created 4 years ago
- Comments:11 (6 by maintainers)
Top GitHub Comments
Worked flawlessly. Thank you so much.
For anyone reading this in the future, using Rails / Webpacker, this is what I did:
In my component.vue:
The css imports didn’t change the layout of my page, which was happening before when I was imported the entire bootstrap CSS file.
Thank you again @tmorehouse