v-tour-guide
v1.2.1
Published
A comprehensive Vue 3 tour guide library with TypeScript support for Vue and Nuxt applications
Maintainers
Readme
Vue Tour Guide
A comprehensive Vue 3 tour guide library with TypeScript support for Vue and Nuxt applications.
Features
- 🎯 Precise Element Targeting - Target elements using CSS selectors or data attributes
- 🎨 Beautiful Tooltips - Customizable tooltips with multiple directions and styling options
- 📱 Responsive Design - Works seamlessly across all device sizes
- 🔄 Real-time Position Tracking - Automatic position updates during scrolling and resizing
- ⚡ Performance Optimized - Efficient rendering with 60fps position monitoring
- 🎪 Flexible Positioning - Support for separate tooltip targeting and custom offsets
- 🔧 TypeScript Support - Full type safety with comprehensive interfaces
- 🎭 Lifecycle Hooks - beforeShow, afterShow, beforeHide hooks for custom logic
- 🌐 Framework Agnostic - Works with Vue 3 and Nuxt 3
- ♿ Accessibility Ready - Built with screen readers and keyboard navigation in mind
Installation
npm install v-tour-guideCSS Import
Important: You need to import the tour guide CSS for proper styling (arrows, animations, etc.):
The stylesheet is fully self-contained — it loads nothing from a CDN, requires no CSS framework, and adds no global resets to your page. It works the same whether your app uses Tailwind, Bootstrap, or plain CSS.
Option 1: Import in your plugin (Recommended)
// plugins/v-tour-guide.client.ts
import { TourGuideManager, TourGuideTooltip } from "v-tour-guide";
import "v-tour-guide/style.css"; // Add this line
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.component("TourGuideManager", TourGuideManager);
nuxtApp.vueApp.component("TourGuideTooltip", TourGuideTooltip);
});Option 2: Import in your component
<script setup lang="ts">
import { useTourGuide, type TourGuideStep } from "v-tour-guide";
import "v-tour-guide/style.css"; // Add this line
</script>Option 3: Add to Nuxt config
// nuxt.config.ts
export default defineNuxtConfig({
css: ["v-tour-guide/style.css"],
// ... rest of your config
});Live Demo
🎮 Try it out: Live Demo
Quick Start
Vue 3 Application
<template>
<div>
<!-- Your app content -->
<div data-tour-guide="welcome">Welcome to our app!</div>
<button data-tour-guide="action-button">Get Started</button>
<!-- Tour Guide Manager -->
<TourGuideManager
:steps="tourSteps"
:auto-start="true"
@complete="onTourComplete"
/>
</div>
</template>
<script setup lang="ts">
import { TourGuideManager, type TourGuideStep } from "v-tour-guide";
const tourSteps: TourGuideStep[] = [
{
id: "welcome",
title: "Welcome!",
content: "This is your first step in the tour.",
target: "welcome",
direction: "bottom",
showAction: true,
},
{
id: "action",
title: "Take Action",
content: "Click this button to get started.",
target: "action-button",
direction: "top",
showAction: true,
},
];
const onTourComplete = () => {
// Tour completed
};
</script>Nuxt 3 Application
- Create a plugin file
plugins/v-tour-guide.client.ts:
import { TourGuideManager, TourGuideTooltip } from "v-tour-guide";
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.component("TourGuideManager", TourGuideManager);
nuxtApp.vueApp.component("TourGuideTooltip", TourGuideTooltip);
});- Use in your pages:
<template>
<div>
<div data-tour-guide="content">Your content here</div>
<TourGuideManager :steps="steps" />
</div>
</template>
<script setup lang="ts">
import { useTourGuide, type TourGuideStep } from "v-tour-guide";
const { startTourGuide } = useTourGuide();
const steps: TourGuideStep[] = [
// Your tour steps
];
</script>API Reference
TourGuideManager Component
Props
| Prop | Type | Default | Description |
| ------------------- | ----------------- | ----------- | ----------------------------------------------------------------- |
| steps | TourGuideStep[] | [] | Array of tour steps |
| autoStart | boolean | false | Auto-start tour when component mounts |
| showOverlay | boolean | true | Show dimming overlay |
| allowSkip | boolean | true | Allow users to skip the tour |
| allowHtml | boolean | false | Render step content as HTML (see Rich content) |
| highlightPadding | number | 4 | Padding around highlighted elements (px) |
| labels | TourGuideLabels | undefined | Global button labels |
| allowInteractions | boolean | false | Allow interactions with other elements during tour |
| scrollToView | boolean | true | Auto-scroll the target into view before highlighting |
| trackAnimations | boolean | false | Poll target position each frame to follow CSS animations (see note) |
| fluid | boolean | false | Ease the highlight/tooltip between steps (matched to scroll); off = instant jump |
| fluidDuration | number | 300 | Fluid transition duration in ms (higher = slower); only used when fluid is on |
trackAnimationsre-measures the target every animation frame. Scrolling, resizing, and DOM changes are tracked without it — only enable it if your target element moves under a CSS animation or transition while a step is showing, since it forces a layout on every frame.
Events
| Event | Payload | Description |
| ------------- | -------------------------------------- | --------------------------- |
| start | void | Tour has started |
| complete | void | Tour completed successfully |
| skip | void | Tour was skipped |
| step-change | (step: TourGuideStep, index: number) | Current step changed |
Exposed Methods
// Start the tour programmatically
tourManager.startTourGuide();
// Skip/stop the tour
tourManager.skipTourGuide();
// Complete the tour
tourManager.completeTourGuide();
// Navigate to specific step
tourManager.goToStep(stepIndex);
// Navigation
tourManager.nextStep();
tourManager.previousStep();
// State access
tourManager.isActive; // readonly ref
tourManager.currentStepIndex; // readonly refTourGuideStep Interface
interface TourGuideStep {
id: string; // Unique step identifier
title: string; // Tooltip title
content?: string; // Tooltip content
allowHtml?: boolean; // Render content as HTML (overrides the manager prop)
target: string; // CSS selector, class, id, or data attribute
tooltipTarget?: string; // Separate element for tooltip positioning
direction?: "top" | "bottom" | "left" | "right"; // Tooltip direction
offsetX?: number; // Horizontal offset (px)
offsetY?: number; // Vertical offset (px)
radius?: number; // Highlight border radius (px)
scrollToView?: boolean; // Auto-scroll to element
showAction?: boolean; // Show action buttons
skipLabel?: string; // Custom skip button label
nextLabel?: string; // Custom next button label
prevLabel?: string; // Custom previous button label
finishLabel?: string; // Custom finish button label
tooltip?: {
// Tooltip customization options
backgroundColor?: string;
textColor?: string;
borderRadius?: string;
padding?: string;
maxWidth?: string;
minWidth?: string;
boxShadow?: string;
buttonBackgroundColor?: string;
buttonTextColor?: string;
buttonHoverColor?: string;
skipButtonColor?: string;
skipButtonHoverColor?: string;
progressActiveColor?: string;
progressInactiveColor?: string;
tooltipClass?: string;
headerClass?: string;
contentClass?: string;
actionsClass?: string;
};
beforeShow?: () => void | Promise<void>; // Pre-show hook
afterShow?: () => void; // Post-show hook
beforeHide?: () => void | Promise<void>; // Pre-hide hook
}TourGuideLabels Interface
interface TourGuideLabels {
skip?: string; // Label for skip button (default: "Skip")
next?: string; // Label for next button (default: "Next")
previous?: string; // Label for previous button (default: "Previous")
finish?: string; // Label for finish button (default: "Finish")
}useTourGuide Composable
const {
tourGuideState, // Reactive state object
startTourGuide, // Start tour function
completeStep, // Complete specific step
finishTourGuide, // Finish/skip tour
resetTourGuide, // Reset tour state
isStepCompleted, // Check if step is completed
} = useTourGuide();Element Targeting
The target property accepts CSS selectors and data attributes:
<!-- Using data attributes (recommended) -->
<div data-tour-guide="welcome">Welcome!</div>
<!-- Using CSS selectors -->
<div id="submit-button">Submit</div>
<div class="feature-list">Features</div>const tourSteps = [
{
id: "welcome",
title: "Welcome!",
target: "welcome", // data-tour-guide="welcome"
content: "Welcome to our app",
},
{
id: "submit",
title: "Submit",
target: "#submit-button", // ID selector
content: "Click to submit",
},
{
id: "features",
title: "Features",
target: ".feature-list", // Class selector
content: "Check out our features",
},
];Tooltip Customization
You can customize tooltip appearance and behavior:
{
id: 'custom-step',
title: 'Custom Styled Tooltip',
content: 'This tooltip has custom styling!',
target: 'my-element',
showAction: true,
tooltip: {
backgroundColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
textColor: '#ffffff',
borderRadius: '1rem',
padding: '1.5rem',
maxWidth: '24rem',
boxShadow: '0 25px 50px -12px rgb(0 0 0 / 0.25)',
buttonBackgroundColor: '#3b82f6',
buttonTextColor: '#ffffff',
buttonHoverColor: '#2563eb'
}
}Rich content
By default content renders as plain text, so any markup you write is escaped.
There are three ways to get formatting.
1. Line breaks — no configuration needed. Newlines in a content string are
preserved:
{
id: 'welcome',
title: 'Welcome',
target: 'welcome-card',
content: 'First line.\nSecond line.'
}2. HTML — opt in with allowHtml. Set it globally on the manager, or per
step to override:
<TourGuideManager :steps="steps" allow-html />{
id: 'welcome',
title: 'Welcome',
target: 'welcome-card',
allowHtml: true,
content: 'Press <kbd>Cmd</kbd>+<kbd>K</kbd> to open <strong>search</strong>.'
}Security:
allowHtmlrenders the string as-is and does not sanitize it. Only enable it for content you author. If step content can come from user input, an API, or a CMS, sanitize it yourself first (e.g. with DOMPurify) or use thecontentslot below instead.
3. Slots — for anything interactive. Use these when you need components, links with handlers, or images rather than a markup string.
Slots
All slots are declared on TourGuideManager and forwarded to the tooltip.
| Slot | Scope | Replaces |
| ------------- | ------------------------------------------------------------------------------------------------------- | ------------------------- |
| content | content, step, stepIndex, currentStep, totalSteps | The tooltip body |
| header | title, step, stepIndex, currentStep, totalSteps | The title row |
| skip-button | skipLabel, onSkip, step, currentStep, totalSteps | The skip button |
| progress | step, stepIndex, currentStep, totalSteps | The progress dots |
| actions | showPrevious, isLastStep, prevLabel, nextLabel, finishLabel, onNext, onPrevious, onSkip | The previous/next buttons |
<TourGuideManager :steps="steps">
<template #content="{ step }">
<p class="mb-2">{{ step.content }}</p>
<a :href="step.docsUrl" class="underline">Read the docs</a>
</template>
<template #actions="{ isLastStep, onNext, onPrevious, showPrevious }">
<button v-if="showPrevious" @click="onPrevious">Back</button>
<button @click="onNext">{{ isLastStep ? 'Done' : 'Continue' }}</button>
</template>
</TourGuideManager>The content slot takes precedence over both allowHtml and the plain
content string.
Advanced Features
Separate Tooltip Positioning
Highlight one element while positioning the tooltip relative to a different element:
{
id: 'complex-step',
title: 'Advanced Feature',
content: 'This highlights one element but positions tooltip elsewhere.',
target: '.main-button', // Element to highlight
tooltipTarget: '.tooltip-anchor', // Different element for tooltip positioning
direction: 'right',
showAction: true
}Lifecycle Hooks
{
id: 'async-step',
title: 'Loading Data',
target: 'data-section',
async beforeShow() {
await fetchData()
},
afterShow() {
analytics.track('tour_step_viewed', { step: 'data-section' })
}
}Auto-scroll Configuration
{
id: 'scroll-step',
title: 'Scroll to View',
target: 'footer-content',
scrollToView: true, // Automatically scrolls element into view
direction: 'top'
}Accessibility
The tour guide is built with accessibility in mind:
- Keyboard Navigation: Full keyboard support for navigation
- Screen Reader Support: Proper ARIA labels and announcements
- Focus Management: Automatic focus handling
- High Contrast Mode: Support for high contrast themes
- Reduced Motion: Respects
prefers-reduced-motionsettings
Examples
Check out the examples/ directory for detailed usage examples:
- Basic Usage - Simple tour implementation
License
MIT License - see LICENSE file for details.
Support
Made with ❤️ for the Vue.js community
