Hi! I will create in this short tutorial a popover (sometimes named as tooltip) component in VueJS. I didn’t use in my example any third-party library, like Bootstrap or Vue Bootstrap. This is a pure tooltip/popover component in VueJS just with JavaScript usage.
Why it is better to create your own popover in VueJS than use external library for that? For me the best explanation is that we have then full control over the created solution and we can easily adapt or modify it when need. And this can be problematic in external solutions.
Table of Contents
Popover on hover over in VueJS – short solution with explanation
I will add here screen shots of my solution of Popover in VueJS code, and next I will focus deeply on each important part.
My very basic popover app in VueJS you can find here:
I created in my VueJS popover/tooltip example in Vue CLI to make it easy and straightforward. I have there 2 key files:
1 – Main application App.vue file – default starting point of Vue CLI app
Code in textual format is at the bottom of this article.
Lets have here a closer look for code above. This is the hosting or parent component code. Let’s check it closer:
- We must normally import here a VueJS Popover component by import statement and put that component into HTML code.
- Key part here is to add a reference
ref="popover"
, which we use in Vue lifecycle hook –updated
. In updated hook we must trigger Popover’s init method always when parent (hosting) vue component is updated.
Why? Because when parent component is updated, than new elements requiring popover might appear there. So popover component must check all HTML elements fordata-popover
property and reinitialize itself for them. - There is also a
v-for
loop andbutton
to generate new links with – to show how reinitializing of vuejs popover goes.
2 – Popover.vue file – component with basic popover
Code in textual format is at the bottom of this article.
This is the key component with popover. Let’s check its most important parts:
Long story short – VueJS popover/tooltip components checks for all elements in parten component which has “data-popover” HTML attribute and assign to it mouse move event to show then a popover.
- First in HTML part we have short HTML code, where
show
variable switches visibility of popover andpositionInlineStyle
computed property sets right position of popover according mouse cursor position over the HTML element with popover. - Key method is
init
. Here we have pure JavaScript code. It is looking for all HTML elements in parent (hosting) component which hasdata-popover
attribute and next assign to eachmousemove
event withÂsetPopoverData
method which defines position and visibility for vuejs popover initialized at moment (when mouse cursor move over the HTML element). - On the beginning of
init
method all previously created events are removed. - At the end the proper CSS styles are applied to show popover/tooltip in a right position and layer.
We can say that whole popover component is based on a JavaScript closer – because data (html/css/vuejs) is used on fly on binded move move event.
VueJS popover – summary
This short example of VueJS popover shows how we can easly create and use our own component to display important information to the user on fly, like a native title
HTML attribute. THis can be done in many ways, here I showed option based on native JavaScript DOM elements, attributes and mouse events together with VueJS component.
VueJS popover – code
- Parent (hosting) VueJS component code:
<template> <div id="app"> <popover ref="popover" /> <a href="https://dev-bay.com" data-popover="This is a popover from Dev-Bay.com!">Link to Dev-Bay.com</a> <div class="more"> <div v-for="(i, k) in q" :key="k"> <a href="https://dev-bay.com" :data-popover="'This is a new link with popover' + i">New link {{i}}</a> </div> <button @click="addLinks">Add more links</button> </div> </div> </template> <script> import Popover from './components/popover.vue' export default { name: 'App', components: { Popover }, data () { return { q: 0, } }, methods: { addLinks () { this.q += 10; } }, updated () { this.$refs.popover.init(); } } </script> <style> #app { width: 500px; margin: 20px auto; } .more, button { margin-top: 20px; } </style>
- Popover VueJS component code:
<template> <div v-show="show" class="popover" :style="positionInlineStyle"> {{txt}} </div> </template> <script> export default { name: 'HelloWorld', data () { return { show: false, txt: '', posX: 0, posY: 0, popovers: [] } }, methods: { init () { this.removeListeners(); this.popovers = this.$parent.$el.querySelectorAll('[data-popover]'); this.popovers.forEach(popover => { popover.addEventListener("mousemove", this.setPopoverData); popover.addEventListener("mouseleave", this.clearData); }); }, removeListeners () { this.popovers.forEach(popover => { popover.removeEventListener("mousemove", this.setPopoverData); popover.removeEventListener("mouseleave", this.clearData); }); this.popovers = []; }, setPopoverData (e) { this.show = true; this.txt = e.target.getAttribute('data-popover'); this.posX = e.x - 10; this.posY = e.y + 30; }, clearData () { this.show = false; this.txt = ''; this.posX = 0; this.posY = 0; } }, computed: { positionInlineStyle () { return `left: ${this.posX}px; top: ${this.posY}px`; } }, mounted () { console.log('mounted'); this.init(); } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .popover { background: #fff; border: 1px solid #ccc; border-radius: 5px; position: absolute; padding: 10px; z-index: 9999; } .popover::before { content: ''; width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 5px solid #ccc; position: absolute; top: 0; left: 10px; transform: translateY(-100%); z-index: 9999; } </style>
- You can check that also here:
Live demo – open here
Github code – open here