agentsclimarketplace

Nextstep tours

Skill jakerains/AgentSkills/skills/nextstep-tours

Build product tours, onboarding flows, and interactive tutorials/lessons in Next.js with NextStep v2 (nextstepjs). Use when adding guided tours, walkthroughs, onboarding overlays, feature callouts, interactive lessons, or gated step-by-step tutorials to a Next.js App Router or Pages Router app. Covers NextStepProvider setup, multi-tour configuration, DOM-anchored and modal steps, multi-page tours with nextRoute/prevRoute, NextStepViewport for scrollable containers, custom card components, validation-gated progression, dark mode, analytics callbacks, and localization. Triggers: nextstep, nextstepjs, product tour, onboarding, walkthrough, guided tour, feature tour, tutorial overlay, interactive lesson, step-by-step guide, useNextStep, NextStepProvider, NextStepViewport, CardComponentProps.From its SKILL.md

Install
npx -y skills add jakerains/AgentSkills --skill nextstep-tours

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

15.5 KB, as published. Nobody here has run it

NextStep Tours Skill

Build product tours, onboarding flows, and β€” most importantly β€” interactive tutorials with NextStep v2 (nextstepjs) in Next.js. This skill makes the action-gated lesson pattern the default rather than generic welcome popups.

Quick Reference

TaskApproachReference
Install & wire provider3-step Quick Startthis file
Define a tourTour / Step schemathis file
Multi-page tournextRoute / prevRoutereferences/multi-page-tours.md
Scrollable containerNextStepViewportreferences/multi-page-tours.md
Custom card UIcardComponent propreferences/custom-card.md
Gate progress on user actionCustom card + validation registryreferences/tutorial-authoring.md
Full props & typesNextStep / Step / CardComponentPropsreferences/api-reference.md
Element not found, SSR, z-indexTroubleshooting tablereferences/troubleshooting.md

Core principle: A tour that just shows tooltips teaches nothing. A tutorial that requires the user to perform each action before advancing teaches. Reach for the validation-gated pattern whenever the word "tutorial" or "lesson" appears.


Install

npm i nextstepjs motion
# or: pnpm add nextstepjs motion / yarn add nextstepjs motion / bun add nextstepjs motion

motion is the peer dependency (the library formerly known as Framer Motion, used for step transitions).

Pages Router users only: if you hit ES module errors at runtime, see references/troubleshooting.md for the next.config.js fix.


Minimal Working Example (App Router)

Three files. Drop-in ready.

1. lib/tours.ts

import type { Tour } from 'nextstepjs';

export const tours: Tour[] = [
  {
    tour: 'welcome',
    steps: [
      {
        icon: 'πŸ‘‹',
        title: 'Welcome',
        content: "Let's take a quick look around.",
        selector: '#welcome-banner',
        side: 'bottom',
        showControls: true,
        showSkip: true,
        pointerPadding: 10,
        pointerRadius: 8,
      },
      {
        icon: '🧭',
        title: 'Navigation',
        content: 'Your main nav lives here.',
        selector: '#main-nav',
        side: 'right',
        showControls: true,
        showSkip: true,
      },
      {
        icon: 'πŸŽ‰',
        title: 'All set',
        content: "You're ready. Explore freely.",
        showControls: true,
      },
    ],
  },
];

2. app/layout.tsx

import { NextStepProvider, NextStep } from 'nextstepjs';
import { tours } from '@/lib/tours';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <NextStepProvider>
          <NextStep steps={tours}>
            {children}
          </NextStep>
        </NextStepProvider>
      </body>
    </html>
  );
}

3. components/start-tour-button.tsx (client component that triggers the tour)

'use client';
import { useNextStep } from 'nextstepjs';

export function StartTourButton() {
  const { startNextStep } = useNextStep();
  return <button onClick={() => startNextStep('welcome')}>Take a tour</button>;
}

Render <StartTourButton /> anywhere inside the provider tree. Add id="welcome-banner" and id="main-nav" to the elements the steps target.


The Step Shape

All props a single step supports β€” required ones first, optional below. Source of truth for every example in this skill.

type Step = {
  // ── Required ──────────────────────────────────────────────
  icon: React.ReactNode | string | null;  // emoji string, JSX, or null
  title: string;                           // step heading
  content: React.ReactNode;                // body (string or JSX)

  // ── Targeting ─────────────────────────────────────────────
  selector?: string;     // CSS #id of the element to anchor to. Omit for a centered modal step.
  side?: 'top' | 'bottom' | 'left' | 'right'
       | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
       | 'left-top' | 'left-bottom' | 'right-top' | 'right-bottom';

  // ── Pointer (the keyhole highlight) ───────────────────────
  pointerPadding?: number;   // px of breathing room around target
  pointerRadius?: number;    // border-radius of keyhole (px)

  // ── Default-card controls (ignored if using a custom card) ─
  showControls?: boolean;    // show Next / Prev buttons
  showSkip?: boolean;        // show Skip button

  // ── Behavior ──────────────────────────────────────────────
  blockKeyboardControl?: boolean;  // disable ←/β†’/Esc for this step (use on form-input steps)
  disableInteraction?: boolean;    // block clicks/hover on the highlighted element (view-only steps)

  // ── Multi-page routing ────────────────────────────────────
  nextRoute?: string;   // route to push when the user clicks Next
  prevRoute?: string;   // route to push when the user clicks Prev

  // ── Scrollable containers ─────────────────────────────────
  viewportID?: string;  // id of a <NextStepViewport> ancestor; positions relative to that container
};

Gotcha: showControls and showSkip only affect NextStep's default card. If you use a custom cardComponent, you must read step.showControls / step.showSkip yourself and render buttons accordingly (see references/custom-card.md).


Step Patterns

DOM-anchored (most common)

{
  icon: 'βš™οΈ',
  title: 'Settings live here',
  content: 'Click the gear to manage your account.',
  selector: '#settings-gear',
  side: 'left',
  showControls: true,
  showSkip: true,
}

Unanchored modal (intro / outro)

// No `selector` β†’ renders as a centered modal at the top of the document body.
{
  icon: 'πŸŽ‰',
  title: 'Welcome aboard',
  content: "This 60-second walkthrough will get you started.",
  showControls: true,
}

Multi-page / routed step

// First page β€” Next pushes /settings, NextStep waits for #settings-header to mount before advancing.
{
  icon: 'πŸ“„',
  title: 'Open settings',
  content: 'Click Next to head to the settings page.',
  selector: '#dashboard-header',
  side: 'bottom',
  showControls: true,
  nextRoute: '/settings',
}

Viewport-confined step (inside a scrollable container)

// Wrap the scrollable element:
<div className="overflow-auto max-h-[400px]">
  <NextStepViewport id="data-table">
    <table>
      <tr id="row-42">…</tr>
    </table>
  </NextStepViewport>
</div>
{
  icon: 'πŸ”',
  title: 'Row 42',
  content: 'Scroll position is handled automatically inside the viewport.',
  selector: '#row-42',
  side: 'top',
  viewportID: 'data-table',
  showControls: true,
}

Action-gated tutorial step (use for lessons)

A step that does not advance until the user performs a real action. Requires a custom card backed by a validation registry. See references/tutorial-authoring.md for the full pattern and assets/validation-card.tsx + assets/validation-registry.ts for drop-in code.

// The step itself looks normal:
{
  icon: '✏️',
  title: 'Type your username',
  content: 'Enter at least 3 characters in the field above.',
  selector: '#username-field',
  side: 'bottom',
  showControls: true,
  blockKeyboardControl: true,  // prevent accidental Esc while typing
}

// The magic lives in the validation registry β€” keyed by [tourName][stepIndex].
// See references/tutorial-authoring.md.

The useNextStep Hook

Every method and property the hook returns. Import from nextstepjs; must be called inside a 'use client' component.

'use client';
import { useNextStep } from 'nextstepjs';

const {
  startNextStep,      // (tourName: string) => void β€” start a specific tour by id
  closeNextStep,      // () => void                  β€” exit the current tour
  currentTour,        // string | null               β€” id of the active tour, or null
  currentStep,        // number                      β€” 0-indexed step pointer
  setCurrentStep,     // (step: number, delay?: number) => void β€” jump to a step (optional ms delay)
  isNextStepVisible,  // boolean                     β€” is the overlay currently rendered
} = useNextStep();

Start on user click

'use client';
import { useNextStep } from 'nextstepjs';

export function HelpButton() {
  const { startNextStep } = useNextStep();
  return <button onClick={() => startNextStep('welcome')} aria-label="Start tour">Help</button>;
}

Auto-start for first-time users only

'use client';
import { useEffect } from 'react';
import { useNextStep } from 'nextstepjs';

export function OnboardingAutostart({ userId }: { userId: string }) {
  const { startNextStep } = useNextStep();

  useEffect(() => {
    const key = `onboarded:${userId}`;
    if (localStorage.getItem(key) === 'true') return;
    startNextStep('welcome');
    localStorage.setItem(key, 'true');
  }, [userId, startNextStep]);

  return null;
}

Never call startNextStep during render β€” always inside useEffect or an event handler.


Analytics & Lifecycle Callbacks

NextStep accepts four lifecycle props. Wire them into your analytics pipeline for funnel visibility.

'use client';
import { NextStep, NextStepProvider } from 'nextstepjs';
import { tours } from '@/lib/tours';
import { track } from '@/lib/analytics';

export function NextStepShell({ children }: { children: React.ReactNode }) {
  return (
    <NextStepProvider>
      <NextStep
        steps={tours}
        onStart={(tourName) => track('tour_started', { tourName })}
        onStepChange={(step, tourName) => track('tour_step_viewed', { tourName, step })}
        onComplete={(tourName) => track('tour_completed', { tourName })}
        onSkip={(step, tourName) => track('tour_skipped', { tourName, step })}
      >
        {children}
      </NextStep>
    </NextStepProvider>
  );
}

Use onComplete to persist a "tutorialDone" flag so the tour never auto-replays. Use onSkip with the step index to learn where users abandon β€” that's your tutorial's weakest link.


Designing Tutorials vs. Welcome Tours

The difference between a forgettable popup parade and a real lesson:

  • Gate progression on action, not clicks. If the user can spam Next without doing the thing, they will. Use a custom card + validation registry (references/tutorial-authoring.md) so "Next" actually requires the user to complete the step's task.
  • One sentence per step. The UI is the teacher; the card is just the label. If content needs more than one sentence, split the step.
  • Always include showSkip: true. People who know the product hate tours. Let them out instantly.
  • Set blockKeyboardControl: true on input steps. Prevents accidental Esc-to-dismiss while the user is typing into a field the step is highlighting.
  • Use disableInteraction: true for view-only steps. Stops the user from clicking the highlighted thing when you want them to read about it, not activate it.
  • Multi-page lessons need placeholder anchors. If step N+1 lives on /settings and that page fetches data async, render a minimal placeholder element with the step's id before the fetch resolves β€” otherwise nextRoute navigates but the step never appears. Details in references/multi-page-tours.md.
  • Branch with separate tours, not conditional steps. For novice-vs-expert paths, define two Tour objects and pick which one to startNextStep() based on user state. One tour = one linear flow.
  • Resume with setCurrentStep(index, delay). On mount, read a persisted step index from localStorage and jump there with a small delay to let the DOM settle. Pair with onStepChange to save progress.
  • Write analytics events per step, not per tour. tour_step_viewed + step_failed_validation tells you which specific step is frustrating users. tour_completed alone doesn't.
  • Localize by generating steps inside a hook. NextStep has no built-in i18n; wrap your tours definition in a function that accepts t() from your i18n library and regenerates when locale changes.

Deeper coverage of each principle, with the full validation registry pattern and 4 real validator archetypes, is in references/tutorial-authoring.md.


Copy-Paste Starters

Drop-in files in assets/:

  • assets/provider-layout.tsx β€” complete App Router layout.tsx wrapping children in NextStepProvider + NextStep with a custom card, callbacks, and all overlay props set to sensible defaults.
  • assets/tours.ts β€” representative multi-tour file: one welcome tour, one feature tour with nextRoute, one gated-lesson tour paired with the validation registry.
  • assets/custom-card.tsx β€” Tailwind + dark-mode aware card, exercises every CardComponentProps field.
  • assets/validation-card.tsx β€” variant that reads from validation-registry.ts, awaits the validator, shows inline error on fail.
  • assets/validation-registry.ts β€” typed [tourName][stepIndex] map with three real validator archetypes (DOM input, async fetch, viewport size).

Copy the files, wire the imports, and adjust selectors/IDs to match your app.


References

  • references/api-reference.md β€” Every prop on NextStep, Step, Tour, CardComponentProps, and NavigationAdapter, with types, defaults, and the full exports list. Read this when you need the authoritative signature for any prop.
  • references/custom-card.md β€” Full paste-ready Tailwind + dark-mode card, the arrow slot, overlay tuning (shadowRgb, shadowOpacity, overlayZIndex, clickThroughOverlay), pointer styling, and accessibility notes.
  • references/multi-page-tours.md β€” nextRoute/prevRoute lifecycle, the placeholder-anchor pattern for async pages, NextStepViewport for scrollable containers, and when a custom navigationAdapter is needed.
  • references/tutorial-authoring.md β€” The differentiating content. Validation registry pattern with four validator archetypes (input, click-tracked, async API, viewport gate), pacing rules, branching strategy, resume-later with localStorage + setCurrentStep, analytics taxonomy, and localization via getLocalizedSteps().
  • references/troubleshooting.md β€” Problem β†’ Fix table covering element-not-found timing, Pages Router ESM errors, dark mode scope, tour re-firing, z-index conflicts, Strict Mode double-invoke, and hydration.

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.