npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

just-a-walkthrough

v0.1.1

Published

Framework-agnostic onboarding walkthrough / product tour library with optional React provider & Tailwind/shadcn support.

Readme

just-a-walkthrough

npm version Bundlephobia License Formatted with Biome Linted with Biome Checked with Biome

Framework‑agnostic, zero‑dependency product tour / onboarding walkthrough with optional React helpers.

Features

  • Spotlight highlight & darkened backdrop (3 panel overlay + focus ring)
  • Accessible keyboard navigation (Esc / Enter / ← →) + focus trap
  • Auto scroll + responsive reposition on scroll/resize/mutations
  • Step hooks (beforeStep / afterStep) & lifecycle callbacks
  • Chain multiple tours with persistence-aware skipping
  • LocalStorage progress persistence & resume support
  • Optional once‑per‑session logic via orchestrator helper
  • Custom tooltip renderer + theming (default, tailwind, unstyled)
  • Works with any DOM (vanilla, React, shadcn, portals)
  • Tiny, tree‑shakeable (no external deps)

Install

npm i just-a-walkthrough
# or
pnpm add just-a-walkthrough
# or
yarn add just-a-walkthrough

Quick Start (Vanilla)

import { startWalkthrough } from 'just-a-walkthrough';

startWalkthrough([
  { selector: '#hero-cta', title: 'Welcome', content: 'Click here to begin.' },
  { selector: '.nav-settings', title: 'Settings', content: 'Manage preferences.' }
]);

React Example

import { useEffect } from 'react';
import { startWalkthrough } from 'just-a-walkthrough';

export function Onboard() {
  useEffect(() => {
    const inst = startWalkthrough([
      { selector: '#dash-metric', title: 'Metrics' },
      { selector: '#create-btn', title: 'Create', content: 'Start something new' },
    ], { persistProgress: true, tourId: 'main-onboarding' });
    return () => inst.destroy();
  }, []);
  return null;
}

Orchestrator (Route-based Tours)

import { registerTours, startAutoMatches } from 'just-a-walkthrough';

registerTours([
  { id: 'home-tour', match: '/home', steps: [ { selector: '#welcome', title: 'Hi!' } ] },
  { id: 'settings-tour', match: '/settings', steps: [ { selector: '#profile', title: 'Profile' } ], oncePerSession: true }
]);

// Call on route change
startAutoMatches({ pathname: window.location.pathname });

API Surface (Core)

startWalkthrough(steps, options) – convenience wrapper returning a Walkthrough instance.

Walkthrough key methods:

  • start(index?) – begin tour (auto called by helper)
  • next()/prev()
  • finish() – mark completed & cleanup
  • skip(reason?)
  • destroy() – cleanup without marking completed

Persistence options (when persistProgress: true & tourId set):

  • Saves { index, completed } in localStorage under __walkthrough:<tourId>
  • Resumes if not completed and resume !== false

Theming

Use theme: 'tailwind' to rely on your Tailwind stack (supply utility classes) or unstyled to supply all styling manually.

Chain Multiple Tours

import { WalkthroughChain } from 'just-a-walkthrough';
new WalkthroughChain([
  { id: 'a', steps: [ { selector: '#x' } ] },
  { id: 'b', steps: [ { selector: '#y' } ], options: { persistProgress: true, tourId: 'b' } }
]).start();

Completed persistent tours are skipped automatically.

React Integration (Provider & Hook)

For React apps you can wrap your tree with the WalkthroughProvider to get easy access to start and chain helpers plus reactive state (current index, active flag):

import { WalkthroughProvider, useWalkthrough } from 'just-a-walkthrough/react';

function LaunchTourButton() {
  const { start, active } = useWalkthrough();
  return (
    <button
      disabled={active}
      onClick={() => start([
        { selector: '#logo', title: 'Logo' },
        { selector: '#settings', title: 'Settings' },
      ], { persistProgress: true, tourId: 'react-main' })}
    >Start Tour</button>
  );
}

export function App() {
  return (
    <WalkthroughProvider>
      <LaunchTourButton />
      {/* rest of app */}
    </WalkthroughProvider>
  );
}

Auto start on mount:

<WalkthroughProvider autoStart={{ steps, options }} />

React Route Orchestrator Component

If you want automatic starting of registered route-based tours when the location changes, use the RouteOrchestrator helper:

import { RouteOrchestrator } from 'just-a-walkthrough/react';
import { registerTours } from 'just-a-walkthrough';

registerTours([
  { id: 'home-tour', match: '/home', trigger: 'auto', steps: [ { selector: '#home-title', title: 'Home' } ] },
  { id: 'profile-tour', match: /\/users\//, trigger: 'auto', steps: [ { selector: '#avatar', title: 'Avatar' } ], order: 10 },
]);

function Routes({ pathname }: { pathname: string }) {
  return (
    <>
      <RouteOrchestrator pathname={pathname} chain onStartIds={ids => console.log('Started tours', ids)} />
      {/* your routed UI */}
    </>
  );
}

Lazy load a module containing tour registrations before matching:

<RouteOrchestrator pathname={pathname} dynamicModule={() => import('./tours')} />

Dev Panel (Development Only)

The optional WalkthroughDevPanel gives you a floating inspector for tours: start them manually, run auto matches, chain matches, and reset persistence.

import { WalkthroughDevPanel } from 'just-a-walkthrough/react';

function Root() {
  return (
    <>
      {/* app UI */}
      {import.meta.env.DEV && <WalkthroughDevPanel chainMatches />}
    </>
  );
}

Features:

  • Lists all registered tours with matcher summary.
  • Shows completion status (persistent tours).
  • Start / Reset per tour; Reset All.
  • Run Matches (or Chain Matches if chainMatches prop true).
  • Collapsible; collapsed state stored in localStorage (__wt_devpanel_collapsed).

Do NOT ship this to production (reveals internal tour structure).

Debugging / Diagnostics

Instrumentation is available but silent by default. To enable and inspect internal events you can use one of:

  1. Build-time env var (e.g. with Vite): JUST_A_WALKTHROUGH_DEBUG=true
  2. Runtime flag: window.__JUST_A_WALKTHROUGH_DEBUG = true
  3. API call: enableDebug(true)

Events recorded include categories: walkthrough (start, step, resolved, missing, finish, skip), orchestrator (registration, match, chain), react (route effects, dynamic loads).

import { enableDebug, dumpWalkthroughDebug, printWalkthroughDebug } from 'just-a-walkthrough/debug';

enableDebug(true);
// run some tours ...

// Safe summary only (counts + meta, no raw events)
printWalkthroughDebug();

// Full detail (explicit opt-in) with redaction example
printWalkthroughDebug({
  full: true,
  redact: e => ({ ...e, data: undefined })
});

const snapshot = dumpWalkthroughDebug(); // programmatic access

Security: by default printWalkthroughDebug() prints only aggregate counts (avoids leaking selectors or user data). Pass { full: true } consciously in trusted environments.

HTML Content Sanitization: step content strings are sanitized by default (removes <script>, <style>, <iframe> etc., strips event handler attributes like onclick, and blocks unsafe URL schemes such as javascript:). This mitigates XSS if tour definitions incorporate user‑generated text. If you absolutely trust the source, set allowUnsafeHTML: true on an individual step to bypass the sanitizer—but prefer leaving it enabled.

You can also access a console proxy wtDebug which is a no-op unless debug is enabled:

import { wtDebug } from 'just-a-walkthrough/debug';
wtDebug.log('current tour id', currentId);

Advanced Usage Notes

  • Use waitMs: 0 (or global stepWaitMs: 0) for elements that are guaranteed to be present to avoid unnecessary polling.
  • Prefer chaining tours when you have progressive disclosure flows; persistent tours auto-skip if already completed, keeping chains idempotent.
  • When dynamically removing highlighted elements mid-step (e.g. route transitions), the MutationObserver repositions but if the element disappears the next navigation call will resolve again. Consider guarding with required steps if element is critical.

Accessibility Notes

  • Focus ring container traps tab order (unless disableFocusTrap: true)
  • Live region announces step titles (aria-live="polite")
  • Esc always available (when keyboard: true)

Zero-Wait Configuration

Specify stepWaitMs: 0 and/or per-step waitMs: 0 to disable polling for elements (single lookup). stepPollIntervalMs is clamped to a minimum of 1ms internally when waiting.

Changelog

This project maintains an automated changelog based on git commits and package.json versions. See CHANGELOG.md for release history and docs/CHANGELOG_GENERATION.md for details on the generation process.

Development

npm i
npm run dev      # playground
npm test         # vitest (jsdom)
npm run build    # library build + types
npm run changelog # generate/update changelog based on commits

Publishing (Maintainers)

npm run build && npm test
npm version patch   # or minor / major
npm run changelog   # update changelog with new version
git push && git push --tags
npm publish --access public

License

AGPL-3.0-only – see LICENSE. For commercial / alternative licensing reach out.


Contributions welcome. Open an issue or PR with ideas / improvements.