How to create a Vue Tooltip component using BootstrapVue tooltip - vue.js

I'm new to Vue and I don't use Bootstrap often so please pardon my newbie question, I'm trying to create a Vue tooltip component, I've created one to behave the way I wanted using css, however, I'm running into some accessibility issues, so I decided to use the BootstrapVue tooltip instead, but I don't know how I would create this component with Bootstrap.
This is basically my Tooltip.vue component using css:
<template>
<div :class="`tooltip ${position}`">
<slot></slot>
<span class="tooltip-text">{{content}}</span>
</div>
</template>
<script>
export default {
name: 'Tooltip',
props: {
position: String,
content: String,
}
};
</script>
<style lang="scss">
.tooltip {
.......
</style>
Then I import and use my component in other places like this:
<tooltip position="right" content="Right tooltip">Hover me</tooltip>
And I have created a TooltipBootstrap.vue component wanting to have the same structure but using Bootstrap, but I don't know how that would go, here is what I started:
I npm installed bootstrap-vue
<template>
<div>
<button v-b-tooltip.hover.${position}="'${content}'"></button>
</div>
</template>
<script>
import VBTooltip from 'bootstrap-vue';
export default {
name: 'TooltipBootstrat',
components: {
VBTooltip,
},
props: {
position: String,
content: String,
}
};
</script>
I'm reading the bootstrap documentation: https://bootstrap-vue.org/docs/directives/tooltip, but I don't know if I'm using this the way it's supposed to be used, so I'm a little lost and would appreciate any help/advice, thanks!

BootstrapVue provide <b-tooltip> component and v-b-tooltip directive (preferred method from document). You can play around in the document.
In simple words, you can use v-b-tooltip directive on any element which is very convenient. but for <b-tooltip> component you have to set target to identify the target to active the tooltip.
So in your case you can do something like:
<template>
<div v-b-tooltip="{ title: content, placement: position }">
<slot></slot>
</div>
</template>
<script>
import { VBTooltip } from 'bootstrap-vue'
export default {
name: 'Tooltip',
directives: {
'b-tooltip': VBTooltip,
},
props: {
position: String,
content: String,
}
};
</script>

Related

Tailwind color not working on dynamic classes Vue + Vite

First time Im using tailwind and I can't figure out why colors are not working. This is a fresh install of Laravel Jetstream which comes with Tailwind, Vue3, Vite & Inertia.
seems like the relevant styling is not imported from tailwind if classes are added dynamically.
Here's some basic component
<template>
<div :class="style" class="border-l-4 p-4" role="alert">
<p><slot name="headline"></slot></p>
<p class="pt-3" v-if="slots.error"><span class="font-bold">Message:</span><slot name="error"></slot></p>
<div class="my-3" v-if="slots.info"><slot name="info"></slot></div>
</div>
</template>
<script setup>
import { useSlots } from 'vue'
const slots = useSlots()
</script>
<script>
export default {
name: 'Alert',
props: {
color: {type: String, default: 'red'}
},
computed: {
style() {
return `bg-${this.color}-100 border-${this.color}-500 text-${this.color}-700`
}
}
}
</script>
and using something like this does not have any color related styling although the class is there
<Alert color="orange" class="my-5">
<template #headline>Test</template>
</Alert>
but if the dynamic classes are also specified somewhere in the same page then everything works.
i.e.
<div class="bg-orange-100 border-orange-500 text-orange-700"></div>
<Alert color="orange" class="my-5">
<template #headline>Test</template>
</Alert>
This was relatively an easy fixed, it was mentioned in here to avoid constructing class name dynamically
https://tailwindcss.com/docs/content-configuration#dynamic-class-names
so, in the computed style I just specify full class name conditionally with all the possible values
changed from this.
style() {
return `bg-${this.color}-100 border-${this.color}-500 text-${this.color}-700`
}
to this
style() {
const styles = {
default : 'bg-cyan-100 border-cyan-500 text-cyan-700',
red : 'bg-red-100 border-red-500 text-red-700',
orange: 'bg-orange-100 border-orange-500 text-orange-700',
green: 'bg-green-100 border-green-500 text-green-700',
blue: 'bg-blue-100 border-blue-500 text-blue-700',
}
return styles[this.color] ?? styles.default
}
now everything works perfectly
The method I always use is to simply put in all the possible classes inside the file when dealing with some basic dynamic classes. I noticed that even if the classes are specified in commented lines, tailwind still import the styling of those classes when found inside any file
here's an example
<template>
<div :class="`bg-${color}-100 border-${color}-500 text-${color}-700`" class="border-l-4 p-4" role="alert">
test
</div>
</template>
<script>
/* all supported classes for color props
bg-red-100 border-red-500 text-red-700
bg-orange-100 border-orange-500 text-orange-700
bg-green-100 border-green-500 text-green-700
bg-blue-100 border-blue-500 text-blue-700
*/
export default {
name: 'Alert',
props: {
color: {type: String, default: 'red'}
}
}
</script>
So now all these would work fine
<Alert color="red"></Alert>
<Alert color="orange"></Alert>
<Alert color="green"></Alert>
<Alert color="blue"></Alert>
but this one wont have any styling as the generated classes for purple are not pre specified in any files
<Alert color="purple"></Alert>

vue single file components naming; is it important?

What's the point of the name of a single file vue component?
In this example:
<template>
<div class="inventory-section">
<draggable v-model="itemSectionProps.itemSectionCategory">
<transition-group>
<div
v-for="category in itemSectionProps.itemSectionCategory"
:key="category.itemSectionCategoryId"
>
<!-- <p>{{ category.itemSectionCategoryName }}</p> -->
<inventory-section-group :itemSectionGroupProps="category">
</inventory-section-group>
</div>
</transition-group>
</draggable>
</div>
</template>
<script>
import InventorySectionGroup from "./InventorySectionGroup";
import draggable from "vuedraggable";
export default {
name: "Inventory",
components: {
InventorySectionGroup,
draggable,
},
inventory section group is named like:
<script>
import InventoryItem from "./InventorySectionGroupItemC";
export default {
name: "Do I even have a point?",
components: {
InventoryItem,
},
props: {
itemSectionGroupData: {
type: Object,
},
},
};
</script>
so, does the name in the component matter?
After some testing, all components seem to work as long as they're translated from camel to kebap-case when imported (and used). Is this the case?
A good justification for the name is that lets say you have a naming convention to your files and for components.
For example if all components are named with what they are but not appended with comp (ie: Inventory.vue instead of InventoryComp.vue) and when you use them you want to be more explicit about what they are (components) so you want to use this component like this: <inventory-comp />. An easy way to do this is to use the name property and set it like this in your Inventory.vue:
name: 'InventoryComp` // or inventory-comp

Need help implementing v-tooltip npm package in my Vue application

I'm trying to implement v-tooltip https://www.npmjs.com/package/v-tooltip in my Vue app in its own component but it's currently not doing anything when I hover the element and I don't get any console errors, I don't know if I'm implementing it correctly and would appreciate any help I can get.
In the same application, I have created a component called TooltipBoot.vue where I'm using the bootstrap tooltip, and this one is working just fine, so I tried to do a similar setup with v-tooltip, but v-tooltip is not working at all.
Here is my TooltipBoot.vue component that works:
<template>
<span v-b-tooltip ="{ title: content, placement: position, trigger: action, variant: theme}">
<slot></slot>
</span>
</template>
<script>
import { VBTooltip } from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
export default {
name: 'TooltipBoot',
directives: {
'b-tooltip': VBTooltip,
},
props: {
position: String,
content: String,
action: String,
theme: String
},
};
</script>
Then I import and use my component in other places:
<tooltip-boot content="Hello" position="top" theme="danger">Hover me</tooltip-boot>
So I tried to do something similar using v-tooltip, this is my VTooltip.vue component:
<template>
<span v-tooltip ="{ content: content}">
<slot></slot>
</span>
</template>
<script>
import { VTooltip } from 'v-tooltip'
export default {
name: 'VTooltip',
directives: {
'tooltip': VTooltip,
},
props: {
content: String,
},
};
</script>
And then I try to use the component:
<v-tooltip content="Hello Tooltip">Hover me </v-tooltip>
but nothing happens when I hover the text, am I missing anything? Or is this not the way to implement this package? Thank you!
I got this tooltip working and forgot to update my question here, the solution was a lot easier than I thought, I just had to add the Sass styles to my component, which can be found at the bottom in the documentation https://www.npmjs.com/package/v-tooltip

Vue: can't use a component inside another compontent

I am trying to use a child compontent in another compontent and it does not work. I have been trying to solve this problem looking for typos etc. for hours, but can't find anything.
Menu.vue
<template>
<div class='navbar-and-alert'>
<alert/>
<nav class='navbar'>
</nav>
</div>
</template>
<script>
import Alert from './Alert.vue'
export default {
name: 'Navbar',
compontents: {
Alert
},
data (){
return {
}
},
}
</script>
Alert.vue
<template>
<section class='alert-section'>
<p class='alert-section__content'>
...
</p>
<a href=''><img src='/static/assets/img/close.svg' class='alert-section__close-icon'></a>
</section>
</template>
<script>
export default {
name: 'Alert',
}
</script>
I get this alert in console:
Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
The alert component works when used inside App.vue
components has a typo:
compontents: {
Alert
},
Should be:
components: {
Alert
},

How to use Onsen UI tabbar with Vue single file components

I'm using Vue Onsen UI and trying to render a Vue single file component for each tab.
In the documentation here, they make use of template in a single page. Which is not very reusable. I want to be able to import custom component and render that.
Here is something that I'm trying to do which doesn't seem to work.
<template lang="html">
<v-ons-page>
<!-- top tab bar -->
<v-ons-tabbar position="top" :index="0">
<v-ons-tab label="Browse" page="TaskList">
</v-ons-tab>
<v-ons-tab label="Second">
</v-ons-tab>
</v-ons-tabbar>
</v-ons-page>
</template>
<script>
import TaskList from './TaskList';
export default {
template: '#main',
components: {
'task-list': TaskList,
},
};
</script>
<style lang="scss">
</style>
Can you suggest anything that I should try?
Instead of using tab objects that reference the components directly, use the :tabs property of the tabbar to set up the pages:
<template lang="html">
<v-ons-page>
<v-ons-tabbar position="top" :index="0" :tabs="tabs">
</v-ons-tabbar>
</v-ons-page>
</template>
<script>
import TaskList from './TaskList';
import SecondPage from './SecondPage';
export default {
template: '#main',
data: function () {
return {
tabs: [
{label: 'Browse', page: TaskList},
{label: 'Second', page: SecondPage}
]
}
}
};
</script>
Also, make sure the root element of the components you reference in the page property are <v-ons-page> elements.
I was having the same difficulty with the following syptoms:
Tabs were not appearing at all
No errors in CLI or in console
Note that I was also using the "Hello World" app that is generated from the CLI (vue init OnsenUI/vue-pwa-webpack hello-world)
Resolution
It was pretty simple in the end: there is a file in the root of the folder called vue-onsen-components.js which has all of the components and some of them are commented out. I had to uncomment the following lines and then the tabs appeared:
export { default as VOnsTab } from 'vue-onsenui/esm/components/VOnsTab'
export { default as VOnsTabbar } from 'vue-onsenui/esm/components/VOnsTabbar'