Easy tooltips, popovers and dropdowns for Vue 2.x with Popper.js integration
—
The v-tooltip directive provides simple tooltip functionality for Vue.js elements. It supports string content, positioning modifiers, configuration objects, and dynamic content including async loading.
Simple string-based tooltips with reactive content support.
// String content
v-tooltip="'Static tooltip text'"
// Reactive property
v-tooltip="tooltipContent"
// Template expression
v-tooltip="'You have ' + count + ' new messages'"Usage Examples:
<template>
<div>
<!-- Static tooltip -->
<button v-tooltip="'Click me!'">Button</button>
<!-- Reactive tooltip -->
<button v-tooltip="dynamicMessage">Dynamic Button</button>
<!-- Expression tooltip -->
<span v-tooltip="'Total: ' + itemCount + ' items'">Items</span>
</div>
</template>
<script>
export default {
data() {
return {
dynamicMessage: 'This updates reactively',
itemCount: 42
};
}
};
</script>Control tooltip placement using directive modifiers.
// Positioning modifiers
v-tooltip.top="content"
v-tooltip.top-start="content"
v-tooltip.top-end="content"
v-tooltip.right="content"
v-tooltip.right-start="content"
v-tooltip.right-end="content"
v-tooltip.bottom="content"
v-tooltip.bottom-start="content"
v-tooltip.bottom-end="content"
v-tooltip.left="content"
v-tooltip.left-start="content"
v-tooltip.left-end="content"
v-tooltip.auto="content"
v-tooltip.auto-start="content"
v-tooltip.auto-end="content"Usage Examples:
<template>
<div>
<!-- Position tooltip at bottom-start -->
<button v-tooltip.bottom-start="'Tooltip positioned at bottom-start'">
Bottom Start
</button>
<!-- Position tooltip on right -->
<button v-tooltip.right="'Right positioned tooltip'">
Right Position
</button>
<!-- Auto positioning -->
<button v-tooltip.auto="'Auto positioned based on available space'">
Auto Position
</button>
</div>
</template>Advanced tooltip configuration using object notation.
interface TooltipConfig {
content: string | function | Promise;
classes?: string | string[];
targetClasses?: string | string[];
html?: boolean;
delay?: number | DelayConfig;
placement?: string;
trigger?: string;
show?: boolean;
offset?: number | string;
container?: string | HTMLElement | false;
boundariesElement?: string | HTMLElement;
template?: string;
arrowSelector?: string;
innerSelector?: string;
autoHide?: boolean;
hideOnTargetClick?: boolean;
loadingClass?: string;
loadingContent?: string;
popperOptions?: any;
}
// Object configuration
v-tooltip="configObject"Usage Examples:
<template>
<div>
<!-- Full configuration object -->
<button v-tooltip="fullConfig">Configured Tooltip</button>
<!-- Dynamic classes -->
<button v-tooltip="classConfig">Custom Classes</button>
<!-- Manual trigger -->
<button v-tooltip="manualConfig">Manual Tooltip</button>
</div>
</template>
<script>
export default {
data() {
return {
fullConfig: {
content: 'Advanced tooltip with custom settings',
placement: 'bottom',
delay: { show: 500, hide: 100 },
html: false,
classes: ['custom-tooltip', 'important'],
offset: 10
},
classConfig: {
content: 'Tooltip with dynamic classes',
classes: this.isImportant ? ['urgent'] : ['normal']
},
manualConfig: {
content: 'Manually controlled tooltip',
trigger: 'manual',
show: this.showTooltip
},
isImportant: true,
showTooltip: false
};
},
methods: {
toggleTooltip() {
this.showTooltip = !this.showTooltip;
}
}
};
</script>Support for asynchronous content loading with loading states.
interface AsyncTooltipConfig {
content: () => Promise<string>;
loadingContent?: string;
loadingClass?: string;
}
// Async content function
v-tooltip="{ content: asyncContentFunction, loadingContent: 'Loading...' }"Usage Examples:
<template>
<div>
<!-- Async content with loading state -->
<button v-tooltip="asyncConfig">Async Content</button>
<!-- Function returning promise -->
<button v-tooltip="promiseConfig">Promise Content</button>
</div>
</template>
<script>
export default {
data() {
return {
asyncConfig: {
content: this.loadTooltipContent,
loadingContent: 'Loading tooltip...',
loadingClass: 'tooltip-loading'
},
promiseConfig: {
content: () => this.fetchUserInfo(this.userId),
loadingContent: 'Fetching user info...'
},
userId: 123
};
},
methods: {
async loadTooltipContent() {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000));
return 'Content loaded from server';
},
async fetchUserInfo(userId) {
const response = await fetch(`/api/users/${userId}`);
const user = await response.json();
return `User: ${user.name} (${user.email})`;
}
}
};
</script>Control when tooltips appear and disappear.
// Trigger options
interface TriggerConfig {
trigger: 'hover' | 'focus' | 'click' | 'manual' | string;
show?: boolean; // For manual trigger
}
// Available triggers
'hover' // Mouse enter/leave
'focus' // Element focus/blur
'click' // Click events
'manual' // Programmatic control
'hover focus' // Multiple triggers (space-separated)Usage Examples:
<template>
<div>
<!-- Click trigger -->
<button v-tooltip="{ content: 'Click to toggle', trigger: 'click' }">
Click Tooltip
</button>
<!-- Focus trigger for inputs -->
<input v-tooltip="{ content: 'Help text', trigger: 'focus' }"
placeholder="Focus me" />
<!-- Manual control -->
<button v-tooltip="manualTooltip" @click="toggleManualTooltip">
Manual Control
</button>
<!-- Multiple triggers -->
<button v-tooltip="{ content: 'Hover or focus', trigger: 'hover focus' }">
Multiple Triggers
</button>
</div>
</template>
<script>
export default {
data() {
return {
manualTooltip: {
content: 'Manually controlled tooltip',
trigger: 'manual',
show: this.isTooltipVisible
},
isTooltipVisible: false
};
},
methods: {
toggleManualTooltip() {
this.isTooltipVisible = !this.isTooltipVisible;
}
}
};
</script>Low-level functions for manual tooltip management.
/**
* Create a tooltip on an element
* @param el - Target HTML element
* @param value - Tooltip configuration
* @param modifiers - Directive modifiers object
* @returns Tooltip instance
*/
function createTooltip(el: HTMLElement, value: any, modifiers?: object): Tooltip;
/**
* Destroy tooltip on an element
* @param el - Target HTML element
*/
function destroyTooltip(el: HTMLElement): void;
/**
* Process tooltip options
* @param options - Raw options object
* @returns Processed options
*/
function getOptions(options: any): ProcessedOptions;
/**
* Get tooltip placement from value and modifiers
* @param value - Directive value
* @param modifiers - Directive modifiers
* @returns Placement string
*/
function getPlacement(value: any, modifiers: object): string;
/**
* Extract content from directive value
* @param value - Directive value
* @returns Content string or false
*/
function getContent(value: any): string | false;Control HTML content rendering for security.
// Global HTML setting
Vue.use(VTooltip, {
defaultHtml: false, // Disable HTML by default for security
});
// Or set directly
VTooltip.options.defaultHtml = false;
// Per-tooltip HTML control
v-tooltip="{ content: '<strong>Bold</strong>', html: true }"Security Warning:
<!-- UNSAFE: User-generated content -->
<button v-tooltip="{ content: userGeneratedContent, html: true }">
Dangerous
</button>
<!-- SAFE: Controlled content -->
<button v-tooltip="{ content: '<em>Emphasis</em>', html: true }">
Safe HTML
</button>
<!-- SAFE: Text-only rendering -->
<button v-tooltip="{ content: userGeneratedContent, html: false }">
Safe Text
</button>interface VueDirective {
bind(el: HTMLElement, binding: DirectiveBinding): void;
update(el: HTMLElement, binding: DirectiveBinding): void;
unbind(el: HTMLElement): void;
}
interface DirectiveBinding {
value: any;
oldValue: any;
modifiers: { [key: string]: boolean };
}Install with Tessl CLI
npx tessl i tessl/npm-v-tooltip