web-virtual-tour
v0.1.4
Published
A lightweight, customizable React component for creating interactive guided tours that highlight elements and walk users through your application
Maintainers
Readme
web-virtual-tour
A lightweight, customizable React component for creating interactive guided tours that highlight elements and walk users through your application.
Features
- 🎯 Element Highlighting - Automatically highlights and scrolls to target elements
- 🔄 Multi-Page Navigation - Seamlessly navigate between pages while maintaining tour state
- 💾 Flexible Storage - Support for localStorage, sessionStorage, API, database, or custom storage
- 🎨 Fully Customizable - Extensive CSS variables for theming
- 📱 Responsive - Works on desktop and mobile devices
- ♿ Accessible - Keyboard navigation and screen reader friendly
- 🚀 Lightweight - Minimal bundle size, no heavy dependencies
- ⚙️ Configurable - Show once, conditional display, custom callbacks
Installation
npm install web-virtual-touror
yarn add web-virtual-touror
pnpm add web-virtual-tourQuick Start
import React from "react";
import { VirtualTour } from "web-virtual-tour";
import "web-virtual-tour/src/VirtualTour.css";
const workflows = {
onboarding: [
{
elementSelector: "#nav-home",
header: "Home",
content: "Jump back to your dashboard.",
hasNextButton: true,
},
{
elementSelector: ".create-btn",
header: "Create",
content: "Start something new here.",
hasBackButton: true,
hasNextButton: true,
},
{
elementSelector: "#settings-gear",
header: "Settings",
content: "Adjust your preferences.",
hasBackButton: true,
hasNextButton: false,
},
],
};
function App() {
return (
<div>
{/* Your app UI */}
<nav>
<a id="nav-home" href="#">Home</a>
<button className="create-btn">+ Create</button>
<button id="settings-gear">⚙️ Settings</button>
</nav>
<VirtualTour workflows={workflows} />
</div>
);
}API Reference
Props
| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| workflows | Object | - | ✅ Yes | Object containing tour step configurations. Each key is a workflow name, value is an array of step objects. |
| showOnce | Boolean | false | No | If true, tour shows only once per user |
| storageKey | String | 'virtual-tour-completed' | No | Storage key for tour completion status |
| storage | Object | defaultStorage (localStorage) | No | Custom storage implementation. Use this to store tour status in API, database, or other storage instead of localStorage |
| enabled | Boolean | true | No | Enable/disable the tour component. Useful for conditional rendering. |
| onFinish | Function | undefined | No | Callback function called when tour finishes (user clicks "End" button). |
| onClose | Function | undefined | No | Callback function called when tour is closed (user clicks X icon). |
| finishRedirectUrl | String | undefined | No | URL to redirect to after tour finishes. If not provided, defaults to /home. |
Step Configuration
Each step in the workflow array can have the following properties:
Required Fields
elementSelector(String) - CSS selector for the element to highlight (e.g.,"#nav-home",".create-btn")header(String) - Title displayed in the tour box headercontent(String) - Description text displayed in the tour box body
Optional Fields
hasNextButton(Boolean) - Show "Next" button (default:truefor non-last steps)nextButtonLabel(String) - Custom label for "Next" button (default:"Next")hasBackButton(Boolean) - Show "Back" button (default:false)backButtonLabel(String) - Custom label for "Back" button (default:"Back")
Multi-Page Navigation
elementType(String) - Set to"link"to enable page navigationnextPage(String) - URL to navigate to when "Next" is clickednextElement(String) - Element selector to highlight on the next pagepreviousPage(String) - URL to navigate back to when "Back" is clickedpreviousElement(String) - Element selector to highlight on the previous page
Usage Examples
Basic Tour
import { VirtualTour } from "web-virtual-tour";
import "web-virtual-tour/src/VirtualTour.css";
const workflows = {
onboarding: [
{
elementSelector: "#feature-1",
header: "Feature 1",
content: "This is your first feature.",
hasNextButton: true,
},
{
elementSelector: "#feature-2",
header: "Feature 2",
content: "This is your second feature.",
hasBackButton: true,
hasNextButton: false,
},
],
};
<VirtualTour workflows={workflows} />Show Tour Only Once
<VirtualTour
workflows={workflows}
showOnce={true}
onFinish={() => console.log("Tour completed!")}
/>Custom Storage
By default, the tour uses localStorage to remember if a user has seen it. Use storage prop to use a different storage method (API, database, sessionStorage, etc.):
// Example: Store tour status in your backend API
const apiStorage = {
get: async (key) => {
const response = await fetch(`/api/tour-status/${key}`);
const data = await response.json();
return data.completed ? 'true' : null;
},
set: async (key, value) => {
await fetch(`/api/tour-status`, {
method: 'POST',
body: JSON.stringify({ key, completed: value === 'true' })
});
},
remove: async (key) => {
await fetch(`/api/tour-status/${key}`, { method: 'DELETE' });
}
};
<VirtualTour
workflows={workflows}
showOnce={true}
storage={apiStorage}
/>Why use custom storage?
- Sync tour status across user's devices
- Store in your database for analytics
- Use sessionStorage for session-only tours
- Integrate with your existing storage system
Multi-Page Navigation
// Page 1
const workflows = {
multiPage: [
{
elementSelector: "#nav-home",
header: "Home",
content: "Click Next to go to Page 2",
hasNextButton: true,
elementType: "link",
nextPage: "/page2",
nextElement: "#nav-about"
}
]
};
// Page 2 (must include same workflow structure)
const workflows = {
multiPage: [
{
elementSelector: "#nav-home",
header: "Home",
content: "This is home",
hasNextButton: true,
elementType: "link",
nextPage: "/page2",
nextElement: "#nav-about"
},
{
elementSelector: "#nav-about",
header: "About",
content: "Click Back to return",
hasBackButton: true,
previousPage: "/",
previousElement: "#nav-home",
hasNextButton: false
}
]
};Conditional Tour Display
const [shouldShowTour, setShouldShowTour] = useState(false);
<VirtualTour
workflows={workflows}
enabled={shouldShowTour}
onFinish={() => setShouldShowTour(false)}
/>
<button onClick={() => setShouldShowTour(true)}>
Start Tour
</button>Utility Functions
import { VirtualTour, resetTour, hasTourBeenCompleted } from "web-virtual-tour";
// Reset tour completion status
resetTour('tour-key');
// Check if tour has been completed
const isCompleted = hasTourBeenCompleted('tour-key');Theming
Customize the tour appearance using CSS variables:
:root {
--virtual-tour-background: #000000;
--virtual-tour-width: 240px;
--tour-button-background-color: #1D5E53;
--tour-button-color: #ffffff;
--highlighted-background-color: #1D5E53;
--highlighted-box-shadow: 0px 0px 10px rgba(0, 0, 50, 0.9);
--blurred-overlay-background-color: rgba(0, 0, 0, 0.391);
--virtual-tour-z-index: 100000;
}See the CSS file for all available CSS variables.
Requirements
- React: >=16.8.0 (hooks support required)
- React DOM: >=16.8.0
- Node.js: >=12.0.0 (for development only)
Browser Support
- Chrome 100+
- Firefox 91+
- Safari 15+
- Edge 100+
- Opera 86+
For older browsers, you may need to add polyfills.
Common Use Cases
- User Onboarding - Guide new users through your application
- Feature Announcements - Highlight new features
- Help System - Contextual help and tooltips
- Training - Interactive tutorials for internal tools
- Product Tours - Showcase key features
Best Practices
Wait for DOM: Ensure elements exist before tour starts
useEffect(() => { // Wait for elements to render const timer = setTimeout(() => setTourReady(true), 500); return () => clearTimeout(timer); }, []);Element Selectors: Use stable, unique selectors
// ✅ Good elementSelector: "#nav-home" elementSelector: "[data-tour='create-button']" // ❌ Avoid elementSelector: ".btn" // Too genericElement Selectors: Use stable, unique selectors
// ✅ Good elementSelector: "#nav-home" elementSelector: "[data-tour='create-button']" // ❌ Avoid elementSelector: ".btn" // Too generic, might match multiple elementsError Handling: Check if elements exist
// The component will warn in console if element is not found // Ensure elements are rendered before tour starts
Troubleshooting
Tour doesn't show
- Check if
enabledprop istrue - Verify
showOnceand storage settings - Ensure elements exist in DOM when tour renders
Elements not highlighting
- Verify
elementSelectormatches elements exactly - Check browser console for warnings
- Ensure elements are visible (not
display: none)
Buttons not visible
- Tour box might be positioned below viewport
- Check CSS for button visibility
- Ensure tour box height fits in viewport
Multi-page navigation not working
- Ensure both pages have the tour component
- Verify
nextElementexists on target page - Check that workflow structure matches on both pages
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
ISC
Author
Arun Raj
Support
For issues, questions, or feature requests, please open an issue on the GitHub repository.
Made with ❤️ for better user onboarding experiences
