npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

Readme

web-virtual-tour

npm version License: ISC

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-tour

or

yarn add web-virtual-tour

or

pnpm add web-virtual-tour

Quick 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 header
  • content (String) - Description text displayed in the tour box body

Optional Fields

  • hasNextButton (Boolean) - Show "Next" button (default: true for 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 navigation
  • nextPage (String) - URL to navigate to when "Next" is clicked
  • nextElement (String) - Element selector to highlight on the next page
  • previousPage (String) - URL to navigate back to when "Back" is clicked
  • previousElement (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

  1. Wait for DOM: Ensure elements exist before tour starts

    useEffect(() => {
      // Wait for elements to render
      const timer = setTimeout(() => setTourReady(true), 500);
      return () => clearTimeout(timer);
    }, []);
  2. Element Selectors: Use stable, unique selectors

    // ✅ Good
    elementSelector: "#nav-home"
    elementSelector: "[data-tour='create-button']"
       
    // ❌ Avoid
    elementSelector: ".btn" // Too generic
  3. Element Selectors: Use stable, unique selectors

    // ✅ Good
    elementSelector: "#nav-home"
    elementSelector: "[data-tour='create-button']"
       
    // ❌ Avoid
    elementSelector: ".btn" // Too generic, might match multiple elements
  4. Error 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 enabled prop is true
  • Verify showOnce and storage settings
  • Ensure elements exist in DOM when tour renders

Elements not highlighting

  • Verify elementSelector matches 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 nextElement exists 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