Easy tooltips, popovers and dropdowns for Vue 2.x with Popper.js integration
—
The VPopover component provides advanced popover functionality with Vue component slots for complex interactive content. It supports extensive customization, event handling, and programmatic control.
Register the VPopover component for use in templates.
// Global registration via plugin
Vue.use(VTooltip);
// Manual component registration
import { VPopover } from 'v-tooltip';
Vue.component('v-popover', VPopover);
// Local component registration
export default {
components: {
VPopover
}
};Simple popover with slot-based content.
// Template usage
<v-popover>
<!-- Trigger element -->
<button>Click me</button>
<!-- Popover content -->
<template slot="popover">
<h3>Popover Title</h3>
<p>Complex content goes here</p>
</template>
</v-popover>Usage Examples:
<template>
<div>
<!-- Basic popover -->
<v-popover>
<button class="btn">Show Info</button>
<template slot="popover">
<div class="popover-content">
<h3>Information</h3>
<p>This is a popover with complex content.</p>
<button @click="handleAction">Action</button>
</div>
</template>
</v-popover>
<!-- Popover with form -->
<v-popover trigger="click">
<button>Edit Settings</button>
<template slot="popover">
<form @submit.prevent="saveSettings">
<input v-model="settings.name" placeholder="Name" />
<input v-model="settings.email" placeholder="Email" />
<button type="submit">Save</button>
</form>
</template>
</v-popover>
</div>
</template>
<script>
export default {
data() {
return {
settings: {
name: '',
email: ''
}
};
},
methods: {
handleAction() {
console.log('Action clicked');
},
saveSettings() {
console.log('Settings saved:', this.settings);
}
}
};
</script>Comprehensive configuration through component props.
interface VPopoverProps {
/** Boolean that shows or hide the popover */
open?: boolean;
/** Boolean that disables the popover */
disabled?: boolean;
/** Popover placement position */
placement?: 'auto' | 'auto-start' | 'auto-end' | 'top' | 'top-start' | 'top-end' |
'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' |
'bottom-end' | 'left' | 'left-start' | 'left-end';
/** Show/Hide delay in milliseconds or object with show/hide properties */
delay?: number | string | { show?: number; hide?: number };
/** Position offset in pixels */
offset?: number | string;
/** Events triggering the popover: 'hover', 'click', 'focus', 'manual', or combinations */
trigger?: string;
/** Container where the popover will be appended */
container?: string | HTMLElement | boolean;
/** DOM element for the popover boundaries */
boundariesElement?: string | HTMLElement;
/** Popper.js options object */
popperOptions?: any;
/** Classes applied to the popover element for theming */
popoverClass?: string | string[];
/** Base classes applied to the popover element */
popoverBaseClass?: string | string[];
/** Wrapper class containing arrow and inner content */
popoverWrapperClass?: string | string[];
/** Arrow element class */
popoverArrowClass?: string | string[];
/** Inner content element class */
popoverInnerClass?: string | string[];
/** Hide the popover if clicked outside */
autoHide?: boolean;
/** Automatically update popover position if its size changes */
handleResize?: boolean;
/** Close all open popovers with different open-group values */
openGroup?: string;
/** Class put on the popover when it's open */
openClass?: string | string[];
/** Custom aria ID for accessibility */
ariaId?: string;
}Usage Examples:
<template>
<div>
<!-- Configured popover -->
<v-popover
:open="isPopoverOpen"
placement="bottom-start"
:delay="{ show: 200, hide: 100 }"
trigger="click"
:offset="10"
popover-class="custom-popover"
:auto-hide="true"
open-group="main-menu"
>
<button>Configured Popover</button>
<template slot="popover">
<div>Popover with custom configuration</div>
</template>
</v-popover>
<!-- Disabled popover -->
<v-popover :disabled="isDisabled">
<button :class="{ disabled: isDisabled }">
{{ isDisabled ? 'Disabled' : 'Enabled' }} Popover
</button>
<template slot="popover">
<div>This popover can be disabled</div>
</template>
</v-popover>
</div>
</template>
<script>
export default {
data() {
return {
isPopoverOpen: false,
isDisabled: false
};
}
};
</script>Comprehensive event system for popover lifecycle management.
interface VPopoverEvents {
/** Emitted when open state changes, enables .sync modifier */
'update:open': (isOpen: boolean) => void;
/** Emitted when popover starts showing */
'show': () => void;
/** Emitted after the show delay */
'apply-show': () => void;
/** Emitted when popover starts hiding */
'hide': () => void;
/** Emitted after the hide delay */
'apply-hide': () => void;
/** Emitted when popover is disposed */
'dispose': () => void;
/** Emitted when popover is closed by clicking outside */
'auto-hide': () => void;
/** Emitted when popover is closed with close directive */
'close-directive': () => void;
/** Emitted when popover is closed because another group was shown */
'close-group': () => void;
/** Emitted when content size changes (requires handleResize: true) */
'resize': () => void;
}Usage Examples:
<template>
<div>
<!-- Event handling -->
<v-popover
:open.sync="isOpen"
@show="onShow"
@hide="onHide"
@apply-show="onApplyShow"
@apply-hide="onApplyHide"
@auto-hide="onAutoHide"
@close-directive="onCloseDirective"
@resize="onResize"
:handle-resize="true"
>
<button>Event Popover</button>
<template slot="popover">
<div>
<p>Popover with event handling</p>
<button v-close-popover>Close</button>
</div>
</template>
</v-popover>
<!-- Sync modifier example -->
<v-popover :open.sync="syncedOpen">
<button>Synced Popover ({{ syncedOpen ? 'Open' : 'Closed' }})</button>
<template slot="popover">
<div>Open state is synced with parent component</div>
</template>
</v-popover>
</div>
</template>
<script>
export default {
data() {
return {
isOpen: false,
syncedOpen: false
};
},
methods: {
onShow() {
console.log('Popover starting to show');
},
onHide() {
console.log('Popover starting to hide');
},
onApplyShow() {
console.log('Popover fully shown after delay');
},
onApplyHide() {
console.log('Popover fully hidden after delay');
},
onAutoHide() {
console.log('Popover auto-hidden by clicking outside');
},
onCloseDirective() {
console.log('Popover closed via close directive');
},
onResize() {
console.log('Popover content resized');
}
}
};
</script>Programmatic control methods for popover instances.
interface VPopoverMethods {
/**
* Manually show the popover
* @param options - Show options
*/
show(options?: { event?: Event; skipDelay?: boolean; force?: boolean }): void;
/**
* Manually hide the popover
* @param options - Hide options
*/
hide(options?: { event?: Event; skipDelay?: boolean }): void;
/**
* Dispose the popover instance
*/
dispose(): void;
}Usage Examples:
<template>
<div>
<!-- Method control -->
<v-popover ref="controlledPopover" trigger="manual" :open="false">
<button @click="showPopover">Show Popover</button>
<template slot="popover">
<div>
<p>Programmatically controlled popover</p>
<button @click="hidePopover">Hide</button>
<button @click="disposePopover">Dispose</button>
</div>
</template>
</v-popover>
<!-- External controls -->
<div class="controls">
<button @click="$refs.controlledPopover.show()">External Show</button>
<button @click="$refs.controlledPopover.hide()">External Hide</button>
<button @click="$refs.controlledPopover.show({ force: true })">Force Show</button>
</div>
</div>
</template>
<script>
export default {
methods: {
showPopover() {
this.$refs.controlledPopover.show({ skipDelay: true });
},
hidePopover() {
this.$refs.controlledPopover.hide({ skipDelay: true });
},
disposePopover() {
this.$refs.controlledPopover.dispose();
}
}
};
</script>Advanced slot-based content with reactive capabilities.
interface VPopoverSlots {
/** Default slot for trigger element */
default: any;
/** Named slot for popover content */
popover: {
/** Whether the popover is currently open */
isOpen: boolean;
};
}Usage Examples:
<template>
<div>
<!-- Scoped slot with state -->
<v-popover>
<!-- Trigger slot -->
<button class="trigger">Click for Details</button>
<!-- Popover content with scoped data -->
<template slot="popover" slot-scope="{ isOpen }">
<div class="popover-content">
<h3>Dynamic Content</h3>
<p>Popover is {{ isOpen ? 'open' : 'closed' }}</p>
<ul>
<li v-for="item in dynamicItems" :key="item.id">
{{ item.name }}
</li>
</ul>
<div class="actions">
<button @click="refreshData">Refresh</button>
<button v-close-popover>Close</button>
</div>
</div>
</template>
</v-popover>
<!-- Component in popover -->
<v-popover>
<button>Show Component</button>
<template slot="popover">
<UserProfile :user-id="selectedUserId" @close="closePopover" />
</template>
</v-popover>
</div>
</template>
<script>
export default {
data() {
return {
dynamicItems: [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' }
],
selectedUserId: 123
};
},
methods: {
refreshData() {
// Simulate data refresh
this.dynamicItems = this.dynamicItems.map(item => ({
...item,
name: `${item.name} (updated)`
}));
},
closePopover() {
// Custom close logic
this.$refs.popover.hide();
}
}
};
</script>Use the v-close-popover directive within popover content.
// Close directive usage
v-close-popover // Basic close
v-close-popover="true" // Explicit enable
v-close-popover="false" // Disable
v-close-popover="condition" // Conditional
v-close-popover.all // Close all popoversUsage Examples:
<template>
<v-popover>
<button>Open Menu</button>
<template slot="popover">
<div class="menu">
<div class="menu-header">
<h3>Menu</h3>
<button v-close-popover class="close-btn">×</button>
</div>
<div class="menu-content">
<a href="#" v-close-popover>Link 1</a>
<a href="#" v-close-popover>Link 2</a>
<button v-close-popover="shouldClose" @click="handleAction">
Conditional Close
</button>
<button v-close-popover.all>Close All Popovers</button>
</div>
</div>
</template>
</v-popover>
</template>
<script>
export default {
data() {
return {
shouldClose: true
};
},
methods: {
handleAction() {
// Perform action
console.log('Action performed');
// Close will happen automatically if shouldClose is true
}
}
};
</script>Advanced styling options and theme customization.
interface PopoverStyling {
/** Custom theme classes */
popoverClass: string | string[];
/** Base structural classes */
popoverBaseClass: string | string[];
/** Wrapper element classes */
popoverWrapperClass: string | string[];
/** Inner content classes */
popoverInnerClass: string | string[];
/** Arrow element classes */
popoverArrowClass: string | string[];
/** Classes applied when open */
openClass: string | string[];
}Usage Examples:
<template>
<div>
<!-- Themed popover -->
<v-popover
popover-class="dark-theme large-popover"
popover-inner-class="custom-inner"
popover-arrow-class="custom-arrow"
open-class="popover-visible"
>
<button>Themed Popover</button>
<template slot="popover">
<div>Custom themed content</div>
</template>
</v-popover>
</div>
</template>
<style>
.dark-theme {
background: #333;
color: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
.large-popover .custom-inner {
padding: 20px;
min-width: 300px;
}
.custom-arrow {
border-color: #333;
}
.popover-visible {
opacity: 1;
transform: scale(1);
transition: all 0.2s ease;
}
</style>Install with Tessl CLI
npx tessl i tessl/npm-v-tooltip