v-onboarding

repository·main·Indexed 42 days ago

https://github.com/fatihsolhan/v-onboarding

A fully-typed, customizable onboarding component for Vue 3 (version 2.12.4) that enables the creation of interactive product tours using tooltips and SVG overlays. It includes a built-in module for Nuxt 3+, support for Vue template refs, customizable UI via slots, and extensive styling options through CSS variables. Features include lifecycle hooks (beforeStep, afterStep), event handling for tour completion (@finish) and early exits (@exit), and Popper.js integration for precise tooltip positioning.

Tokens
20.9K
Snippets
78
Records
88
Agent score
51%

What's inside v-onboarding

  1. What is v-onboarding?

    main

    v-onboarding is a lightweight, fully-typed onboarding component designed for Vue 3. It enables developers to create interactive product tours and user guides. Key features include:

    • SVG Overlay: Precise element highlighting with customizable padding and border radius.
    • Smart Positioning: Automatic tooltip placement powered by Popper.js.
    • Customizable UI: Full control over appearance using Vue slots.
    • Lifecycle Hooks: Support for beforeStep and afterStep to handle asynchronous operations.
    • Focus Management: Optional focus trap for improved accessibility.
    • TypeScript Support: Comprehensive type definitions for a better developer experience.
  2. Overview of v-onboarding features

    main

    v-onboarding is a fully-typed, customizable onboarding component designed for Vue 3. It provides a guided tour experience with the following core capabilities:

    • SVG Overlay: Precise element highlighting with customizable padding, border radius, and overlay opacity.
    • Smart Positioning: Automatic tooltip positioning that adapts to viewport boundaries using Popper.js.
    • Full Customization: Complete control over step appearance using Vue slots.
    • Lifecycle Hooks: Support for beforeStep and afterStep hooks to handle async operations, analytics, or state management.
    • Focus Management: Optional focus trap to ensure keyboard navigation remains within the tour interface.
    • TypeScript Support: Comprehensive type definitions for a robust developer experience.
  3. Use Lifecycle Hooks in v-onboarding

    main

    Lifecycle hooks allow you to execute custom logic at specific points during the onboarding tour. You can define these hooks within the on property of a step configuration. Hooks can be asynchronous and are useful for data fetching, UI synchronization, or analytics tracking.

    There are two primary step hooks:

    • beforeStep: Executes before a step is displayed. Use this for preparing the UI or loading necessary data.
    • afterStep: Executes after a user leaves a step. Use this for cleanup or tracking step completion.
    {
      on: {
        beforeStep: async ({ index, step, direction }) => {
          // Logic before step
        },
        afterStep: ({ index, step, direction }) => {
          // Logic after step
        }
      }
    }
  4. Use VOnboardingStep for custom slot content

    main

    When providing custom content via slots, you must wrap your custom UI inside the VOnboardingStep component. This ensures that the onboarding system maintains proper positioning and overlay functionality for your custom elements.

    <template>
      <VOnboardingWrapper ref="wrapper" :steps="steps">
        <template #default="{ step, next, isLast }">
          <VOnboardingStep>
            <div class="my-custom-tooltip">
              <h3>{{ step.content?.title }}</h3>
              <button @click="next">
                {{ isLast ? 'Finish' : 'Next' }}
              </button>
            </div>
          </VOnboardingStep>
        </template>
      </VOnboardingWrapper>
    </template>
    
    <script setup>
    import { VOnboardingWrapper, VOnboardingStep } from 'v-onboarding'
    </script>
  5. Configure tour steps in v-onboarding

    main

    A tour is composed of an array of Step objects. Each step defines where the tooltip should attach, what content to display, and optional behaviors or lifecycle hooks.

    Each step follows this structure:

    • attachTo.element: A CSS selector, a getter function, or a Vue template ref used to target the element for the tooltip.
    • content: An optional object containing title and description strings.
    • options: Optional StepOptions for customizing placement, scrolling, and overlay.
    • on: Optional lifecycle hooks (beforeStep, afterStep) to run logic during the step transition.
    interface Step {
      attachTo: {
        element: string | (() => Element | null) | Ref<Element | null>
      }
      content?: {
        title?: string
        description?: string
      }
      options?: StepOptions
      on?: {
        beforeStep?: () => void | Promise<void>
        afterStep?: () => void | Promise<void>
      }
    }
  6. Manually set up v-onboarding in Nuxt

    main

    If you prefer not to use the Nuxt module, you can manually register the components via a client-side plugin. Ensure the file has a .client.ts suffix to prevent server-side execution errors.

    // plugins/v-onboarding.client.ts
    import { VOnboardingWrapper, VOnboardingStep } from 'v-onboarding'
    import 'v-onboarding/dist/style.css'
    
    export default defineNuxtPlugin((nuxtApp) => {
      nuxtApp.vueApp.component('VOnboardingWrapper', VOnboardingWrapper)
      nuxtApp.vueApp.component('VOnboardingStep', VOnboardingStep)
    })
  7. Attach tour steps to elements

    main

    You can target elements for your tour steps using three different methods within the attachTo.element property:

    1. CSS Selectors: Use standard string selectors (e.g., #id, .class).
    2. Vue Template Refs: Pass a Vue ref directly to the element property. This is recommended for elements without unique IDs.
    3. Getter Functions: Provide a function that returns an Element or null. This is useful for elements that are rendered dynamically or change in the DOM.

    Examples

    CSS Selector:

    { attachTo: { element: '#my-button' } }

    Vue Template Ref:

    <template>
      <button ref="myButton">Click me</button>
      <VOnboardingWrapper :steps="steps" />
    </template>
    
    <script setup>
    import { ref } from 'vue'
    import { VOnboardingWrapper } from 'v-onboarding'
    
    const myButton = ref(null)
    const steps = [{ attachTo: { element: myButton }, content: { title: 'Click here' } }]
    </script>

    Getter Function:

    { attachTo: { element: () => document.querySelector('.dynamic-element') } }
    // CSS Selector
    const steps = [
      { attachTo: { element: '#my-button' }, content: { title: 'Click here' } },
      { attachTo: { element: '.nav-item:first-child' }, content: { title: 'Navigation' } }
    ]
    
    // Getter Function
    const steps = [
      {
        attachTo: {
          element: () => document.querySelector('.dynamic-element')
        },
        content: { title: 'Dynamic element' }
      }
    ]
  8. Handle positioning manually without VOnboardingStep

    main

    If you require complete control over the UI layout and want to handle positioning yourself (e.g., using a Modal or a Teleport), you can omit the VOnboardingStep wrapper.

    Warning: By omitting VOnboardingStep, you lose automatic Popper.js positioning and the SVG overlay functionality.

    <template>
      <VOnboardingWrapper ref="wrapper" :steps="steps">
        <template #default="{ step, next }">
          <!-- No VOnboardingStep wrapper - you handle positioning -->
          <Teleport to="body">
            <div class="my-modal-overlay">
              <div class="my-modal">
                {{ step.content?.title }}
                <button @click="next">Continue</button>
              </div>
            </div>
          </Teleport>
        </template>
      </VOnboardingWrapper>
    </template>
  9. Show conditional custom UI for specific steps

    main

    You can use the index prop from the default slot to conditionally render different UIs for specific steps. For steps where you want the default behavior, you can use VOnboardingStep without any children or with a v-else block.

    <template>
      <VOnboardingWrapper ref="wrapper" :steps="steps">
        <template #default="{ step, next, exit, index }">
          <!-- Custom UI for step 3 (index 2) -->
          <VOnboardingStep v-if="index === 2">
            <MySpecialTooltip
              :title="step.content?.title"
              @next="next"
              @close="exit"
            />
          </VOnboardingStep>
    
          <!-- Default UI for all other steps -->
          <VOnboardingStep v-else />
        </template>
      </VOnboardingWrapper>
    </template>
  10. Basic Setup of v-onboarding

    main

    To implement a basic onboarding tour, follow these three steps:

    1. Import the component and styles: Import VOnboardingWrapper and useVOnboarding from v-onboarding, and include the CSS file v-onboarding/dist/style.css.
    2. Define your steps: Create an array of step objects. Each step requires an attachTo property (specifying the target element via a selector) and a content property (containing title and description).
    3. Set up the wrapper and composable: Use the VOnboardingWrapper component in your template and pass it a ref. Use the useVOnboarding composable, passing the wrapper ref to it, to gain control over the tour lifecycle.
    <template>
      <VOnboardingWrapper ref="wrapper" :steps="steps" />
    
      <!-- Your app content -->
      <button id="step-1">First Element</button>
      <div id="step-2">Second Element</div
    </template>
    
    <script setup>
    import { ref, onMounted } from 'vue'
    import { VOnboardingWrapper, useVOnboarding } from 'v-onboarding'
    import 'v-onboarding/dist/style.css'
    
    const wrapper = ref(null)
    const { start, finish, goToStep } = useVOnboarding(wrapper)
    
    const steps = [
      {
        attachTo: { element: '#step-1' },
        content: { title: 'Welcome!', description: 'Let us show you around.' }
      },
      {
        attachTo: { element: '#step-2' },
        content: { title: 'Features', description: 'Here are the key features.' }
      }
    ]
    
    // Start the tour when component mounts
    onMounted(() => start())
    </script>
  11. Dynamically theme the onboarding overlay and tooltips

    main

    You can change the appearance of the onboarding overlay and tooltips dynamically as the user progresses through steps. This is achieved by applying CSS classes to a parent container and using the beforeStep hook within your step definitions to update that class.

    Implementation Strategy

    1. Wrap the application: Place a container around your VOnboardingWrapper and your page content. This container will hold the dynamic theme class.
    2. Use Step Hooks: In each step object, use the on.beforeStep hook to update a reactive variable that controls the parent container's class.
    3. Clean up: Listen to the @finish and @exit events on VOnboardingWrapper to remove the theme class when the tour ends.
    4. CSS Variables: Use the provided CSS variables to control the overlay color and opacity.
    <template>
      <div :class="currentTheme">
        <VOnboardingWrapper
          ref="wrapper"
          :steps="steps"
          @finish="clearTheme"
          @exit="clearTheme"
        />
        <!-- Page content -->
      </div>
    </template>
    
    <script setup>
    import { ref } from 'vue'
    import { VOnboardingWrapper, useVOnboarding } from 'v-onboarding'
    
    const wrapper = ref(null)
    const { start } = useVOnboarding(wrapper)
    const currentTheme = ref('')
    
    const clearTheme = () => {
      currentTheme.value = ''
    }
    
    const steps = [
      {
        attachTo: { element: '#hero' },
        content: { title: 'Welcome', description: '...' },
        on: {
          beforeStep: () => currentTheme.value = 'theme-accent'
        }
      }
    ]
    </script>
    
    <style>
    .theme-accent {
      --v-onboarding-overlay-fill: #d4ff00;
      --v-onboarding-overlay-opacity: 0.08;
    }
    
    /* You can also style the tooltip components specifically for this theme */
    .theme-accent .v-onboarding-item {
      border-color: #d4ff00;
    }
    </style>