Skip to content
/ nudge Public

Nudge is a lightweight, Vue-first library for building in-app tutorials and product walkthroughs.

License

Notifications You must be signed in to change notification settings

stwic/nudge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Vue Nudge

Interactive tutorial library for Vue 3 applications. Inspired by tutorials from games like Crusader Kings 3 and Europa Universalis V. Made primarily because all the other free options did not have the features I needed. Still a work in progress with customization incoming.

npm version

npm downloads

Features

  • 🎯 Interactive Tutorials - Step-by-step guided experiences with spotlight effects
  • ⏸️ Wait for Actions - Pause tutorial until user performs specific actions
  • 🚫 Block Interactions - Control what users can interact with during tutorials
  • πŸ“ Smart Positioning - Auto-adjusts popover placement to stay visible
  • πŸ“œ Auto-scroll - Automatically scrolls to keep elements and popovers in view
  • ⏭️ Skip Sections - Allow users to jump between tutorial sections
  • πŸ”„ Reactive Updates - ResizeObserver and MutationObserver for dynamic content
  • πŸ“ TypeScript - Full type safety and IntelliSense support

Installation

npm install vue-nudge
# or
yarn add vue-nudge
# or
pnpm add vue-nudge

Quick Start

1. Add Tutorial component to your app

<template>
  <div>
    <YourApp />
    <Tutorial />
  </div>
</template>

<script setup lang="ts">
import { Tutorial } from 'vue-nudge'
</script>

2. Create a tutorial configuration

import type { TutorialConfig } from 'vue-nudge'

export const myTutorialConfig: TutorialConfig = {
  id: 'my-first-tutorial',
  showProgress: true,
  allowClose: true,

  steps: [
    {
      id: 'welcome',
      title: 'Welcome! πŸ‘‹',
      description: 'Let me show you around',
      placement: 'center'
    },
    {
      id: 'click-button',
      target: '[data-tutorial="my-button"]',
      title: 'Click This Button',
      description: 'Go ahead, click it!',
      placement: 'bottom',
      blockInteractions: false,
      waitForAction: {
        event: 'button-clicked',
        timeout: 30000
      }
    },
    {
      id: 'explore',
      target: '[data-tutorial="feature-panel"]',
      title: 'Explore This Feature',
      description: 'This panel contains important information',
      placement: 'right',
      allowSkipTo: ['final-step']
    },
    {
      id: 'final-step',
      title: 'All Done! πŸŽ‰',
      description: 'You're ready to go!',
      placement: 'center'
    }
  ],

  onComplete: () => {
    console.log('Tutorial completed!')
  },

  onClose: () => {
    console.log('Tutorial closed')
  }
}

3. Add data attributes to your elements

<template>
  <button data-tutorial="my-button" @click="handleClick">
    Click Me
  </button>

  <div data-tutorial="feature-panel">
    Feature content here
  </div>
</template>

4. Start the tutorial

<script setup lang="ts">
import { getTutorial } from 'vue-nudge'
import { myTutorialConfig } from './config/myTutorial'

const tutorial = getTutorial()

function startTutorial() {
  tutorial.start(myTutorialConfig)
}

function handleClick() {
  // Trigger tutorial progression when user clicks
  tutorial.triggerAction('button-clicked')
}
</script>

<template>
  <button @click="startTutorial">Start Tutorial</button>
</template>

API Reference

TutorialConfig

interface TutorialConfig {
  id: string                    // Unique identifier for this tutorial
  steps: TutorialStep[]         // Array of tutorial steps
  showProgress?: boolean        // Show progress indicator (default: true)
  allowClose?: boolean          // Allow closing tutorial (default: true)
  onComplete?: () => void       // Callback when tutorial completes
  onClose?: () => void          // Callback when tutorial is closed/skipped
}

TutorialStep

interface TutorialStep {
  id: string                    // Unique step identifier
  title: string                 // Step title
  description: string           // Step description (supports HTML)
  target?: string               // CSS selector for highlighted element
  placement?: 'top' | 'bottom' | 'left' | 'right' | 'center'
  blockInteractions?: boolean   // Block clicks on other elements
  waitForAction?: {
    event: string               // Event name to wait for
    timeout?: number            // Optional timeout in ms
  }
  allowSkipTo?: string[]        // Step IDs that can be skipped to
  popoverClass?: string         // Additional CSS class for popover
  onEnter?: () => void | Promise<void>
  onExit?: () => void | Promise<void>
}

Tutorial Methods

const tutorial = getTutorial()

// Start a tutorial
await tutorial.start(config: TutorialConfig)

// Navigation
await tutorial.next()          // Go to next step
await tutorial.previous()      // Go to previous step
await tutorial.skipTo(stepId: string)  // Skip to specific step

// Control
tutorial.complete()            // Mark tutorial as complete
tutorial.close()               // Close/cancel tutorial

// Events
tutorial.triggerAction(actionName: string, data?: any)
tutorial.on(event: string, handler: Function)
tutorial.off(event: string, handler: Function)

// Utility
tutorial.isCompleted(tutorialId: string): boolean
tutorial.resetCompletion(tutorialId: string)

Advanced Usage

Waiting for User Actions

{
  id: 'expand-menu',
  target: '[data-tutorial="menu"]',
  title: 'Open the Menu',
  description: 'Click to expand this menu',
  waitForAction: {
    event: 'menu-expanded',
    timeout: 30000  // 30 second timeout
  }
}

Then in your component:

<script setup>
import { getTutorial } from 'vue-nudge'

const tutorial = getTutorial()

function expandMenu() {
  // ... your menu logic
  tutorial.triggerAction('menu-expanded')
}
</script>

Skip Buttons

Allow users to skip sections of the tutorial:

{
  id: 'beginner-tips',
  title: 'Tips for Beginners',
  description: 'Some helpful advice...',
  allowSkipTo: ['advanced-features', 'final-step']
}

This will show skip buttons like "Skip to Advanced Features β†’"

Custom Styling

Override default styles with CSS variables or by targeting classes:

.tutorial-popover {
  --tutorial-primary-color: #ff1493;
  --tutorial-bg-color: #1e293b;
  --tutorial-border-radius: 12px;
}

.tutorial-overlay__glow {
  /* Customize glow effect */
}

Dynamic Content

The tutorial automatically tracks size and position changes:

<template>
  <div data-tutorial="expanding-panel" :class="{ expanded }">
    <!-- Content that changes size -->
  </div>
</template>

The spotlight and popover will automatically adjust when the panel expands!

Examples

Check out the examples/ directory for complete working examples:

  • Basic tutorial
  • Multi-step onboarding flow
  • Form validation tutorial
  • Feature tour

TypeScript Support

Full TypeScript support with comprehensive type definitions:

import type {
  TutorialConfig,
  TutorialStep,
  TutorialState,
  TutorialEventType
} from 'vue-nudge'

Browser Support

  • Chrome/Edge 88+
  • Firefox 78+
  • Safari 14+

Requires:

  • Vue 3.3+
  • ResizeObserver API
  • MutationObserver API

Contributing

Contributions are currently closed, but will be open in near future!

License

license MIT License - see LICENSE file for details

Credits

Built by Amir Talic for game-quality user experiences.

Inspired by tutorials from:

  • Crusader Kings 3
  • Europa Universalis V
  • Cities: Skylines 2

About

Nudge is a lightweight, Vue-first library for building in-app tutorials and product walkthroughs.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published