NextStep

repository·main·Indexed 21 days ago

https://github.com/enszrlu/nextstep

A lightweight onboarding library for Next.js and React applications that provides step-by-step guided tours with smooth animations powered by motion. It supports multiple frameworks including Next.js, React Router, and Remix via navigation adapters, and features keyboard navigation, custom card components, and a hook-based API for controlling tours.

Tokens
6K
Snippets
20
Records
28
Agent score
76%

What's inside nextstepjs

  1. Overview of NextStep

    main

    NextStep is a lightweight onboarding library designed for Next.js and React applications. It uses motion for smooth animations and is compatible with multiple React frameworks, including Next.js, React Router, and Remix.

    Key use cases include:

    • Step-by-step tours for user onboarding.
    • Interactive help documentation to increase engagement.
    • Contextual error handling by showing users exactly where to fix issues via tailored tours.
    • Event-based tours triggered by specific user actions.
  2. Define a Tours Array

    main

    NextStep supports multiple independent tours. You can define an array of Tour objects, where each tour has a unique tour name and its own array of steps.

    import { Tour } from 'nextstepjs';
    
    const steps: Tour[] = [
      {
        tour: 'firstTour',
        steps: [
          // Step objects
        ],
      },
      {
        tour: 'secondTour',
        steps: [
          // Step objects
        ],
      },
    ];
  3. Keyboard navigation in NextStep

    main

    NextStep includes built-in support for keyboard navigation to improve accessibility and user experience:

    • Right Arrow: Move to the next step.
    • Left Arrow: Move to the previous step.
    • Escape: Skip the current tour.
  4. Implement localization in NextStep

    main
    NextStep does not include built-in localization support. To implement multi-language support, you should dynamically supply the steps array to your tour configuration based on the user's current locale.
  5. Configure Navigation Adapters for routing

    main

    NextStep 2.0 uses framework-agnostic navigation adapters to handle routing. Each adapter is packaged separately to minimize bundle size. You must import the specific adapter for your framework to ensure features like nextRoute and prevRoute work correctly.

    Next.js

    Next.js is the default adapter for the NextStep component, so no manual import is required.

    import { NextStep, NextStepProvider } from 'nextstepjs';
    
    export default function Layout({ children }) {
      return (
        <NextStepProvider>
          <NextStep steps={steps}>{children}</NextStep>
        </NextStepProvider>
      );
    }

    React Router

    Use NextStepReact combined with the useReactRouterAdapter from nextstepjs/adapters/react-router.

    import { NextStepProvider, NextStepReact } from 'nextstepjs';
    import { useReactRouterAdapter } from 'nextstepjs/adapters/react-router';
    
    export default function App() {
      return (
        <NextStepProvider>
          <NextStepReact navigationAdapter={useReactRouterAdapter} steps={steps}>
            <Outlet />
          </NextStepReact>
        </NextStepProvider>
      );
    }

    Remix

    Use NextStepReact combined with the useRemixAdapter from nextstepjs/adapters/remix.

    import { NextStepProvider, NextStepReact } from 'nextstepjs';
    import { useRemixAdapter } from 'nextstepjs/adapters/remix';
    
    export default function App() {
      return (
        <NextStepProvider>
          <NextStepReact navigationAdapter={useRemixAdapter} steps={steps}>
            <Outlet />
          </NextStepReact>
        </NextStepProvider>
      );
    }
    // Example for React Router
    import { NextStepProvider, NextStepReact } from 'nextstepjs';
    import { useReactRouterAdapter } from 'nextstepjs/adapters/react-router';
    
    export default function App() {
      return (
        <NextStepProvider>
          <NextStepReact navigationAdapter={useReactRouterAdapter} steps={steps}>
            <Outlet />
          </NextStepReact>
        </NextStepProvider>
      );
    }
  6. Configure Vite for NextStepjs

    main

    If using Vite with React Router or Remix, you must perform two steps to prevent build errors:

    1. Configure SSR and Mock Next.js Navigation: Add nextstepjs and motion to noExternal in your vite.config.ts. You also need to mock next/navigation because NextStepjs may attempt to access it.

    2. Create a Mock File: Create /src/mocks/next-navigation.ts with the following content:

    export const useRouter = () => ({
      push: () => {},
      replace: () => {},
      prefetch: () => {},
      back: () => {},
      forward: () => {},
      refresh: () => {},
    });
    
    export const usePathname = () => '';
    export const useSearchParams = () => new URLSearchParams();
    export const useParams = () => ({});
    1. Update Vite Alias: Update vite.config.mts to alias next/navigation to your mock file.
    import path from 'node:path';
    import { defineConfig } from 'vite';
    import react from '@vitejs/plugin-react';
    
    export default defineConfig({
      ssr: {
        noExternal: ['nextstepjs', 'motion'],
      },
      plugins: [react()],
      resolve: {
        alias: [
          {
            find: 'next/navigation',
            replacement: path.join(process.cwd(), 'src/mocks/next-navigation.ts'),
          },
        ],
      },
    });
    export default defineConfig({
      ssr: {
        noExternal: ['nextstepjs', 'motion'],
      },
      // ... alias configuration
    });
  7. Install nextstepjs and motion

    main

    Install the required dependencies using your preferred package manager. You must install both nextstepjs and motion.

    # npm
    npm i nextstepjs motion
    # pnpm
    pnpm add nextstepjs motion
    # yarn
    yarn add nextstepjs motion
    # bun
    bun add nextstepjs motion
  8. Troubleshoot Next.js Pages Router ESM errors

    main

    If you encounter module export errors in the Next.js Pages Router, it is likely a mismatch between ES modules (used by nextstepjs) and CommonJS. To resolve this, update your next.config.js to enable esmExternals and transpile nextstepjs:

    /** @type {import('next').NextConfig} */
    const nextConfig = {
      reactStrictMode: true,
      experimental: {
        esmExternals: true,
      },
      transpilePackages: ['nextstepjs'],
    };
    
    export default nextConfig;
    const nextConfig = {
      experimental: {
        esmExternals: true,
      },
      transpilePackages: ['nextstepjs'],
    };
  9. Implement a Custom Card component

    main

    To gain full control over the design of the onboarding card, provide a cardComponent to the NextStep or NextStepReact component. Your component must implement the CardComponentProps interface.

    Available Props:

    • step: The current Step object (contains icon, title, content, etc.).
    • currentStep: The index of the current step.
    • totalSteps: Total number of steps.
    • nextStep: Function to advance to the next step.
    • prevStep: Function to go back to the previous step.
    • arrow: An SVG object for the pointer (orientation controlled by side).
    • skipTour: Function to skip the tour.
    'use client';
    import type { CardComponentProps } from 'nextstepjs';
    
    export const CustomCard = ({
      step,
      currentStep,
      totalSteps,
      nextStep,
      prevStep,
      skipTour,
      arrow,
    }: CardComponentProps) => {
      return (
        <div className="my-custom-card">
          <h1>{step.icon} {step.title}</h1>
          <h2>{currentStep} of {totalSteps}</h2>
          <p>{step.content}</p>
          <button onClick={prevStep}>Previous</button>
          <button onClick={nextStep}>Next</button>
          <button onClick={skipTour}>Skip</button>
          {arrow}
        </div>
      );
    };
  10. Customize the Arrow/Caret

    main

    You can customize the default SVG caret using arrowStyle or replace it entirely with arrowComponent on the NextStep component.

    Tweak the built-in caret

    Use arrowStyle to pass CSS properties (like color or size) to the existing SVG.

    <NextStep steps={steps} arrowStyle={{ color: '#6d28d9' }}>
      {children}
    </NextStep>

    Replace the arrow entirely

    Provide a component to arrowComponent. The component receives side (the resolved placement) and style (the computed positioning). Important: You must spread the provided style so the arrow remains anchored to the card.

    const MyArrow = ({ side, style }: ArrowComponentProps) => (
      <div style={{ ...style }} data-side={side}>
        ◆
      </div>
    );
    
    <NextStep steps={steps} arrowComponent={MyArrow}>
      {children}
    </NextStep>
    const MyArrow = ({ side, style }: ArrowComponentProps) => (
      <div style={{ ...style }} data-side={side}>
        ◆
      </div>
    );
    
    <NextStep steps={steps} arrowComponent={MyArrow}>
      {children}
    </NextStep>;
  11. Control the tour with the useNextStep hook

    main

    The useNextStep hook allows you to trigger or terminate a tour from any component within your application. It provides two primary methods: startNextStep(tourName: string) to navigate to a specific tour by name, and closeNextStep() to end the current tour.

    import { useNextStep } from 'nextstepjs';
    
    // ... inside a component
    const { startNextStep, closeNextStep } = useNextStep();
    
    const onClickHandler = (tourName: string) => {
      startNextStep(tourName);
    };
  12. Configure the Step Object

    main

    A Step object defines the content and behavior for a single point in a tour.

    PropTypeDescription
    iconReact.ReactNode, string, nullOptional icon/element for the title.
    titlestringThe step title.
    contentReact.ReactNodeThe main body content.
    selectorstringThe CSS selector (e.g., #id) to target.
    side`