Skip to content

Instantly share code, notes, and snippets.

@netadror
Created January 21, 2026 11:45
Show Gist options
  • Select an option

  • Save netadror/85f4157ad917e51bd0ce1713a7b251c8 to your computer and use it in GitHub Desktop.

Select an option

Save netadror/85f4157ad917e51bd0ce1713a7b251c8 to your computer and use it in GitHub Desktop.
GUIDED_TOURS_IMPLEMENTATION_GUIDE

Guided Tours Implementation Guide for React Applications using Driver.js library

This guide is based on a production implementation by Neta Dror ^___^ - Adapt the patterns to fit your specific needs.

This guide provides a step-by-step approach to implementing interactive walkthroughs/guided tours in React applications using Driver.js. This methodology can be adapted to any React project.


Table of Contents

  1. Library Selection
  2. Implementation Steps
  3. Architecture Overview
  4. One-Shot Implementation Prompt
  5. Best Practices

Library Selection

Criteria for Choosing a Walkthrough Library

When selecting a walkthrough library, consider:

Criteria Why It Matters
Bundle Size Keep your app lightweight - aim for <10KB gzipped
License MIT/Apache preferred for commercial use
Dependencies Zero dependencies = fewer security vulnerabilities
Maintenance Actively maintained = bug fixes and updates
Customization Must support custom HTML/CSS in popovers
Framework Agnostic Works with React via DOM refs, not React-specific

Recommended: Driver.js

Why Driver.js?

  • ✅ ~5KB gzipped
  • ✅ MIT License
  • ✅ Zero dependencies
  • ✅ Actively maintained
  • ✅ Highly customizable (custom HTML/CSS in popovers)
  • ✅ Framework agnostic (works with React, Vue, Angular, vanilla JS)

Installation:

npm install driver.js
npm install --save-dev @types/driver.js  # If types are available

Note: Driver.js may not have official TypeScript types. You may need to create your own type definitions or use @types/driver.js if available.

Alternative Libraries:

  • Intro.js - More features but heavier (~50KB)
  • Shepherd.js - Good but requires more setup
  • React Joyride - React-specific, good if you want React components

Implementation Steps

Step 1: Project Planning & Documentation

Create an implementation plan document (WALKTHROUGH_IMPLEMENTATION_PLAN.md):

  1. List all pages/components that need walkthroughs
  2. Categorize by priority (high/medium/low)
  3. Define user roles (if applicable) - which tours show for which users
  4. Document existing guide content - extract from modals/tooltips
  5. Create a checklist - track progress per page

Why this matters: Having a plan prevents scope creep and ensures consistency.


Step 2: Core Infrastructure Setup

2.1 Create Walkthrough Context

File: src/contexts/WalkthroughContext.tsx

Purpose: Global state management for all walkthroughs

Key Features:

  • Track completion status per tour
  • Persist to backend
  • Provide start/stop/reset functions
  • Handle sidebar/modal opening during tours

Type Definitions:

// src/types/walkthrough.ts
export interface WalkthroughStatuses {
  [tourName: string]: boolean;
}

export interface WalkthroughContextType {
  walkthroughStatuses: WalkthroughStatuses;
  activeTour: string | null;
  startWalkthrough: (tourName: string) => Promise<void>;
  stopWalkthrough: () => void;
  markComplete: (tourName: string) => Promise<void>;
  resetAllWalkthroughs: () => Promise<void>;
  getAllWalkthroughStatuses: () => WalkthroughStatuses;
  isCompleted: (tourName: string) => boolean;
}

Structure:

// Pseudo-code structure
interface WalkthroughContextType {
  // State
  walkthroughStatuses: Record<string, boolean>;
  activeTour: string | null;
  
  // Functions
  startWalkthrough(tourName: string): Promise<void>;
  stopWalkthrough(): void;
  markComplete(tourName: string): Promise<void>;
  resetAllWalkthroughs(): Promise<void>;
  getAllWalkthroughStatuses(): Record<string, boolean>;
}

2.2 Create Reusable Hook

File: src/hooks/useWalkthrough.ts

Purpose: Easy integration in any component

Type Definitions:

// src/types/walkthrough.ts
export interface UseWalkthroughReturn {
  start: () => Promise<void>;
  stop: () => void;
  reset: () => Promise<void>;
  isCompleted: boolean;
  isActive: boolean;
  steps: DriverStep[];
  hasSteps: boolean;
}

Usage:

const { start, stop, isCompleted, reset } = useWalkthrough('toolName');

Benefits:

  • Consistent API across all components
  • Auto-loads step configuration
  • Handles completion tracking
  • Full TypeScript type safety

2.3 Create Step Configuration

File: src/config/walkthroughSteps.ts

Purpose: Centralized step definitions

Type Definitions:

// src/types/walkthrough.ts
import { Step as DriverStep } from 'driver.js';

export type PopoverSide = 'top' | 'right' | 'bottom' | 'left' | 'center';
export type PopoverAlign = 'start' | 'center' | 'end';

export interface PopoverConfig {
  title: string;
  description: string;
  side?: PopoverSide;
  align?: PopoverAlign;
}

export interface WalkthroughStep extends Omit<DriverStep, 'popover'> {
  element?: string;
  popover?: PopoverConfig;
  onHighlightStarted?: (element: Element) => void;
  onNextClick?: () => void;
}

export interface WalkthroughSteps {
  [tourName: string]: WalkthroughStep[];
}

Structure:

import { WalkthroughSteps } from '../types/walkthrough';

export const walkthroughSteps: WalkthroughSteps = {
  toolName: [
    {
      popover: {
        title: 'Welcome',
        description: 'Introduction text',
        side: 'center',
        align: 'center'
      }
    },
    {
      element: '[data-walkthrough="element-id"]',
      popover: {
        title: 'Feature Name',
        description: 'Explanation',
        side: 'bottom',
        align: 'start'
      }
    }
  ]
};

Key Points:

  • Use data-walkthrough attributes for element targeting
  • Left-align descriptions with lists/long content
  • Use semantic HTML in descriptions for better formatting
  • Full TypeScript type safety with Driver.js types

2.4 Create Custom Styles

File: src/styles/walkthrough.css

Purpose: Match your app's design system

Key Customizations:

  • Overlay color/opacity (soft grey recommended)
  • Popover styling (match your modals/dialogs)
  • Button colors (match primary brand color)
  • Z-index management (ensure proper layering)

Step 3: Integration Pattern

3.1 Add Provider to App Root

File: src/App.tsx

import { WalkthroughProvider } from './contexts/WalkthroughContext';
import './styles/walkthrough.css';

function App(): JSX.Element {
  return (
    <WalkthroughProvider>
      {/* Your app */}
    </WalkthroughProvider>
  );
}

export default App;

3.2 Add Data Attributes to Target Elements

In your components:

<button data-walkthrough="start-button">
  Start
</button>

TypeScript Support:

// Extend React HTML attributes if needed
declare module 'react' {
  interface HTMLAttributes<T> {
    'data-walkthrough'?: string;
  }
}

Why data attributes?

  • Non-intrusive (doesn't affect styling/functionality)
  • Easy to identify tour targets
  • Works with any element
  • Type-safe with TypeScript declarations

3.3 Integrate Hook in Each Page

Pattern:

import { useWalkthrough } from '../hooks/useWalkthrough';

interface MyComponentProps {
  // Your component props
}

function MyComponent({}: MyComponentProps): JSX.Element {
  const { start, isCompleted } = useWalkthrough('myTool');
  
  return (
    <div>
      <h1>My Tool</h1>
      <button onClick={start} className="start-tour-btn">
        {isCompleted ? 'Replay Tour' : 'Start Tour'}
      </button>
    </div>
  );
}

export default MyComponent;

Step 4: UI Components

4.1 "Start Tour" Button

Placement:

  • Next to page title (always visible)
  • Inside guide modals (optional)

Styling:

  • Match your primary button style
  • Use icon + text for clarity
  • Show "Replay" vs "Start" based on completion

4.2 Help Menu (Optional but Recommended)

Location: Header/navigation bar

Features:

  • List all available tours
  • Show completion status (checkmarks)
  • Organize by category
  • "Reset All" option

Benefits:

  • Easy access to all tours
  • Visual progress tracking
  • Better UX than hidden tours

Step 5: Content Strategy

5.1 Extract Existing Content

Sources:

  • Existing guide modals
  • Tooltips
  • Documentation
  • Help text

Why: Reuse content ensures consistency and saves time.

5.2 Structure Tour Steps

Best Practices:

  1. Start with welcome - No element, center popover
  2. Highlight key features - 3-5 main elements
  3. End with next steps - Guide users forward
  4. Keep it short - 5-8 steps max per page

5.3 Write Clear Descriptions

Do:

  • Use left-aligned text for lists
  • Include emojis for visual interest
  • Break long content into bullets
  • Use semantic HTML (<strong>, <ul>, etc.)

Don't:

  • Write novels (keep it concise)
  • Use jargon without explanation
  • Assume prior knowledge

Step 6: Advanced Features

6.1 Dynamic Sidebar/Modal Opening

Challenge: Highlight sidebar items when sidebar is closed

Solution: Use onHighlightStarted callback to programmatically open sidebar before highlighting

onHighlightStarted: (element: Element): void => {
  if (element.matches('[data-walkthrough="sidebar-item"]')) {
    openSidebar();
  }
}

Type-Safe Implementation:

const handleHighlightStarted = (element: Element): void => {
  if (element instanceof HTMLElement && 
      element.matches('[data-walkthrough="sidebar-item"]')) {
    openSidebar();
  }
};

6.2 Role-Based Tours

Implementation:

  • Check user role before showing tour
  • Filter tour list in Help menu
  • Conditionally render "Start Tour" buttons

6.3 Nested Page Tours

Strategy:

  • Main tool page = main tour
  • Nested pages = separate tours
  • Don't show nested tours in Help menu (only main tools)
  • Access nested tours via "Start Tour" button on each page

Step 7: Testing & Refinement

7.1 Test Checklist

  • All tours start/stop correctly
  • Completion status persists
  • Reset functionality works
  • Tours work on mobile
  • Z-index layering correct (overlays don't block elements)
  • Sidebar/modal opening works
  • Content is clear and helpful

7.2 Common Issues & Fixes

Issue: Overlay blocks highlighted element

  • Fix: Increase z-index of highlighted element

Issue: Popover text not aligned

  • Fix: Use text-align: left in CSS and wrap descriptions in <div>

Issue: Sidebar items not visible during tour

  • Fix: Programmatically open sidebar before highlighting

Issue: Checkmarks hard to see on hover

  • Fix: Use softer grey hover color (#e8e8e8 instead of #f8f8f8)

Architecture Overview

┌─────────────────────────────────────────┐
│         WalkthroughContext              │
│  (Global State Management)              │
│  - Completion tracking                  │
│  - Start/stop/reset functions           │
│  - Backend persistence                  │
└──────────────┬──────────────────────────┘
               │
               ├─── useWalkthrough Hook
               │    (Per-component integration)
               │
               ├─── walkthroughSteps Config
               │    (Step definitions)
               │
               └─── Driver.js
                    (DOM manipulation & UI)

Data Flow:

  1. User clicks "Start Tour"
  2. useWalkthrough hook calls startWalkthrough('toolName')
  3. WalkthroughContext loads steps from config
  4. Driver.js initializes and starts tour
  5. On completion, status saved to backend
  6. UI updates (checkmark appears, button changes)

One-Shot Implementation Prompt

Use this prompt with an AI assistant to get a complete implementation:

I want to implement interactive guided tours/walkthroughs for my React application. Here's what I need:

**Requirements:**
1. Use Driver.js library (lightweight, framework-agnostic)
2. Create a context provider for global state management
3. Create a reusable hook (useWalkthrough) for easy integration
4. Centralized step configuration file
5. Custom CSS to match my design system
6. Support for:
   - Completion tracking (persist to backend)
   - Role-based tours (optional)
   - Dynamic sidebar/modal opening during tours
   - Help menu listing all tours
   - Reset functionality

**My App Details:**
- Framework: React [version] with TypeScript
- State Management: [Context API / Redux / etc.]
- Backend: [Firestore / REST API / etc.]
- UI Library: [Material-UI / Tailwind / etc.]
- Primary Color: [your color]

**Pages That Need Tours:**
[List your pages/components]

**Existing Content:**
[If you have guide modals/tooltips, mention them]

Please provide:
1. Complete WalkthroughContext.tsx with backend persistence and TypeScript types
2. useWalkthrough.ts hook with full type definitions
3. walkthroughSteps.ts structure with TypeScript interfaces (with examples)
4. walkthrough.css with customizable theme variables
5. Integration examples for App.tsx and a sample component with TypeScript
6. Help menu component (TypeScript)
7. Type definitions file (types/walkthrough.ts) with all interfaces
8. Best practices for content writing
9. Common issues and solutions

Make the code production-ready with:
- Full TypeScript type safety (no `any` types)
- Error handling with proper error types
- Type definitions for Driver.js if needed
- Comments explaining key decisions
- Proper React component typing (JSX.Element, React.FC, etc.)

Best Practices

1. Content Writing

Keep it concise:

  • 1-2 sentences per step
  • Use bullets for lists
  • Left-align longer content

Be helpful:

  • Explain "why" not just "what"
  • Include next steps
  • Link to detailed guides

Visual aids:

  • Use emojis sparingly (1-2 per tour)
  • Use <strong> for emphasis
  • Structure with HTML (<ul>, <ol>, <div>)

2. Technical Implementation

Performance:

  • Lazy load Driver.js (code splitting)
  • Don't initialize tours until needed
  • Clean up event listeners on unmount

Accessibility:

  • Ensure keyboard navigation works
  • Add ARIA labels to tour buttons
  • Test with screen readers

TypeScript Best Practices:

  • Create a central types/walkthrough.ts file for all type definitions
  • Use interface for object shapes, type for unions/intersections
  • Avoid any - use unknown if type is truly unknown
  • Use generic types for reusable patterns
  • Export types from a single location for easy imports
  • Use as const for literal types in step configs
  • Define proper return types for all functions (Promise<void>, JSX.Element, etc.)

Example Type-Safe Step Config:

const stepConfig = {
  toolName: [
    {
      popover: {
        title: 'Welcome',
        description: 'Introduction',
        side: 'center' as const,
        align: 'center' as const
      }
    }
  ]
} as const satisfies WalkthroughSteps;

Maintainability:

  • Keep step configs in one file
  • Use consistent naming (data-walkthrough="kebab-case")
  • Document complex callbacks
  • Use TypeScript interfaces for type safety
  • Create shared type definitions file
  • Use type guards for runtime checks

3. User Experience

Don't force tours:

  • Always provide "Skip" option
  • Make tours optional, not mandatory
  • Allow replay anytime

Show progress:

  • Display step counter ("2 of 5")
  • Show completion status (checkmarks)
  • Provide reset option

Respect user state:

  • Don't show completed tours as "new"
  • Remember user preferences
  • Don't interrupt active workflows

4. Design Consistency

Match your app:

  • Use brand colors
  • Match button styles
  • Use same typography
  • Follow spacing system

Visual hierarchy:

  • Overlay should be subtle (not black)
  • Popovers should stand out
  • Highlighted elements should be clear

Quick Start Checklist

For a new implementation, follow this order:

  • Day 1: Planning

    • List all pages needing tours
    • Create implementation plan document
    • Extract existing guide content
  • Day 2: Infrastructure

    • Install Driver.js and TypeScript types
    • Create type definitions file (types/walkthrough.ts)
    • Create WalkthroughContext.tsx
    • Create useWalkthrough.ts hook
    • Create walkthroughSteps.ts config structure
    • Create walkthrough.css
  • Day 3: Integration

    • Add provider to App.tsx
    • Add data attributes to 1-2 test pages
    • Integrate hook in test pages (with TypeScript)
    • Test basic tour flow
    • Verify TypeScript compilation (no type errors)
  • Day 4: Content & Polish

    • Write tour content for all pages
    • Add "Start Tour" buttons
    • Create Help menu
    • Style to match design system
  • Day 5: Testing & Refinement

    • Test all tours
    • Fix z-index issues
    • Test on mobile
    • Get user feedback

Example File Structure

src/
├── types/
│   └── walkthrough.ts (Type definitions)
├── contexts/
│   └── WalkthroughContext.tsx
├── hooks/
│   └── useWalkthrough.ts
├── config/
│   └── walkthroughSteps.ts
├── styles/
│   └── walkthrough.css
├── components/
│   └── Header.tsx (Help menu)
└── pages/
    ├── Homepage.tsx (with tour)
    ├── Tool1.tsx (with tour)
    └── Tool2.tsx (with tour)

Key Takeaways

  1. Start with a plan - Document everything before coding
  2. Build infrastructure first - Context, hook, config, styles
  3. Use data attributes - Non-intrusive element targeting
  4. Reuse existing content - Don't rewrite guides
  5. Test thoroughly - Especially z-index and mobile
  6. Keep it simple - 5-8 steps per tour max
  7. Make it optional - Always allow skip/reset

TypeScript Setup

Type Definitions for Driver.js

If Driver.js doesn't have official types, create your own:

// src/types/driver.d.ts
declare module 'driver.js' {
  export type PopoverSide = 'top' | 'right' | 'bottom' | 'left' | 'center';
  export type PopoverAlign = 'start' | 'center' | 'end';

  export interface PopoverConfig {
    title?: string;
    description?: string;
    side?: PopoverSide;
    align?: PopoverAlign;
    showButtons?: boolean;
    doneBtnText?: string;
    closeBtnText?: string;
    nextBtnText?: string;
    prevBtnText?: string;
    showProgress?: boolean;
    progressText?: string;
  }

  export interface Step {
    element?: string | Element;
    popover?: PopoverConfig;
    onHighlightStarted?: (element: Element) => void;
    onHighlighted?: (element: Element) => void;
    onDeselected?: (element: Element) => void;
    onDestroyStarted?: (element: Element) => void;
    onDestroyed?: (element: Element) => void;
  }

  export interface DriverOptions {
    animate?: boolean;
    opacity?: number;
    padding?: number;
    allowClose?: boolean;
    overlayClickNext?: boolean;
    doneBtnText?: string;
    closeBtnText?: string;
    nextBtnText?: string;
    prevBtnText?: string;
    showProgress?: boolean;
    progressText?: string;
    steps?: Step[];
    onHighlightStarted?: (element: Element, step: Step) => void;
    onHighlighted?: (element: Element, step: Step) => void;
    onDeselected?: (element: Element, step: Step) => void;
    onDestroyStarted?: (element: Element, step: Step) => void;
    onDestroyed?: (element: Element, step: Step) => void;
    onNextClick?: (element: Element, step: Step) => void;
    onPrevClick?: (element: Element, step: Step) => void;
    onCloseClick?: (element: Element, step: Step) => void;
    onDestroyed?: () => void;
  }

  export default class Driver {
    constructor(options?: DriverOptions);
    drive(steps: Step[]): void;
    moveNext(): void;
    movePrevious(): void;
    destroy(): void;
    isActive(): boolean;
    getActiveIndex(): number;
    getActiveStep(): Step | null;
    refresh(): void;
  }
}

tsconfig.json Considerations

Ensure your tsconfig.json includes:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "skipLibCheck": true
  },
  "include": [
    "src/**/*",
    "src/types/**/*.d.ts"
  ]
}

Resources


This guide is based on a production implementation by Neta Dror ^___^ - Adapt the patterns to fit your specific needs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment