← All @molecule/* packages · App templates

@molecule/app-tour-shepherd

Provider bond · tour · App (browser) · v1.0.1 · Apache-2.0

Headless step-state tour provider for @molecule/app-tour (no built-in UI)

npm install @molecule/app-tour-shepherd

npm · Source on GitHub · Implements @molecule/app-tour

How it works

@molecule/app-tour-shepherd is a provider bond on the app (browser) side: it implements the tour core interface (@molecule/app-tour) with a concrete vendor or library behind it.

Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.

// REQUIRED — also `import 'shepherd.js/dist/css/shepherd.css'` in your app
// entry (see @remarks), or the tooltip/buttons/overlay render unstyled.
import { provider } from '@molecule/app-tour-shepherd'
import { setProvider, requireProvider } from '@molecule/app-tour'

setProvider(provider) // once, at startup (bonds.ts)

const tour = requireProvider().createTour({
  steps: [{ target: '[data-mol-id="editor"]', title: 'Editor', content: 'Write code here' }],
  onComplete: () => markTourSeen(),
})
tour.start() // shepherd renders the anchored tooltip + overlay

Works with: @molecule/app-tour

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Shepherd.js v15 tour provider for @molecule/app-tour.

A real, rendering tour provider: createTour() builds a live Shepherd.Tour from the core tour options and shepherd draws the actual step tooltips, highlight, and modal overlay on screen. start / next / previous / cancel / complete drive the shepherd instance, and the core's active-state + step index stay in sync with shepherd's events. This replaces the previous headless step-state machine — the package now depends on and uses shepherd.js, as its name promises.

Quick Start

// REQUIRED — also `import 'shepherd.js/dist/css/shepherd.css'` in your app
// entry (see @remarks), or the tooltip/buttons/overlay render unstyled.
import { provider } from '@molecule/app-tour-shepherd'
import { setProvider, requireProvider } from '@molecule/app-tour'

setProvider(provider) // once, at startup (bonds.ts)

const tour = requireProvider().createTour({
  steps: [{ target: '[data-mol-id="editor"]', title: 'Editor', content: 'Write code here' }],
  onComplete: () => markTourSeen(),
})
tour.start() // shepherd renders the anchored tooltip + overlay

Type

provider

Installation

npm install @molecule/app-tour-shepherd @molecule/app-tour shepherd.js

API

Interfaces

ShepherdConfig

Provider-level defaults for the Shepherd tour provider.

overlay sets the default for shepherd's modal backdrop (useModalOverlay) and the resolved hasOverlay() flag; showButtons sets whether nav buttons are rendered and the resolved hasButtons() flag. A per-tour TourOptions.overlay / TourOptions.showButtons overrides them; if neither is set, both default to true. labels provides the nav-button text.

interface ShepherdConfig {
  /**
   * Default for the modal backdrop / `hasOverlay()` when a tour does not set
   * `overlay`. Feeds shepherd's `useModalOverlay`. Defaults to `true`.
   */
  overlay?: boolean

  /**
   * Default for whether nav buttons render / `hasButtons()` when a tour does
   * not set `showButtons`. Defaults to `true`.
   */
  showButtons?: boolean

  /**
   * Labels for the rendered nav buttons. Supply translated strings; each
   * omitted label falls back to its English default.
   */
  labels?: ShepherdLabels
}

ShepherdLabels

Labels for the nav buttons shepherd renders in each step's footer.

shepherd.js draws real buttons, so the bond has to supply their text. These are user-facing strings — pass them already translated, e.g. { back: t('tour.back', {}, { defaultValue: 'Back' }), … }. Any label left unset falls back to its English default (Back / Next / Done).

interface ShepherdLabels {
  /** Label for the "back" button (shown on every step after the first). Defaults to `Back`. */
  back?: string

  /** Label for the "next" button (shown on every step before the last). Defaults to `Next`. */
  next?: string

  /** Label for the "done" button (shown on the last step). Defaults to `Done`. */
  done?: string
}

Functions

createProvider(config)

Creates a Shepherd-based tour provider.

function createProvider(config?: ShepherdConfig): TourProvider
  • config — Optional provider-level defaults for the resolved overlay / showButtons flags and the nav-button labels.

Returns: A configured TourProvider.

Constants

provider

Default Shepherd tour provider instance.

const provider: TourProvider

Core Interface

Implements @molecule/app-tour interface.

Bond Wiring

Setup function to register this provider with the core interface:

import { setProvider } from '@molecule/app-tour'
import { provider } from '@molecule/app-tour-shepherd'

export function setupTourShepherd(): void {
  setProvider(provider)
}

Injection Notes

Requirements

Peer dependencies:

  • @molecule/app-tour ^1.0.1

Runtime Dependencies

  • @molecule/app-tour

  • shepherd.js

  • Import shepherd's stylesheet yourself — this package does not: import 'shepherd.js/dist/css/shepherd.css' in your app entry. Without it the tooltip, buttons, arrow, and modal overlay render unstyled/invisible (same as quill/photoswipe's theme CSS).

  • Browser-only. start() runs new Shepherd.Tour(...).start(), which needs a live DOM — start tours in a client-only effect, never during SSR.

  • Step mapping. Each core TourStep maps to a shepherd step: targetattachTo.element (CSS selector), placementattachTo.on (defaults to 'bottom' so the tooltip anchors with an arrow), titletitle, contenttext, action → shepherd's per-step when.show hook, beforeShowbeforeShowPromise.

  • overlayuseModalOverlay. The resolved overlay flag (per-tour TourOptions.overlay → provider default → true) becomes shepherd's useModalOverlay, so the darkened backdrop is rendered by shepherd itself and mirrored on hasOverlay().

  • showButtons gates the nav buttons. When the resolved showButtons flag is true, each step gets Back / Next (or Done on the last step) buttons that drive the tour; when false, no buttons are added. hasButtons() mirrors the flag.

  • Button labels are UI text. shepherd renders the buttons, so the bond supplies their labels via ShepherdConfig.labels — pass translated strings (createProvider({ labels: { next: t('tour.next', {}, { defaultValue: 'Next' }) } })); omitted labels fall back to English Back / Next / Done. Step title/content are the consumer's to i18n via t('key', v, { defaultValue }).

  • target is a CSS selector: prefer stable [data-mol-id="…"] selectors over styling class names (class strings are ClassMap-bond-owned and swappable).

  • Wire it with setProvider() from @molecule/app-tour or bond('tour', provider) — both write the same registry slot.

E2E Tests

Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual onboarding flow, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip. The provider only tracks state, so every checkpoint is about the overlay the app RENDERS from getCurrentStep() — verify what's on screen, not just the calls:

  • Starting the tour renders step 1's tooltip (its title/content) anchored to that step's target element, with the target highlighted / spotlighted. start() alone paints nothing — the per-step action is what draws the overlay, so confirm the anchored tooltip actually appears.
  • next advances in order: the tooltip + highlight move to each step's target and the progress indicator updates (e.g. "2 of 5" — getCurrentStep() is zero-based, so it reads step+1 of steps.length). previous moves one step back. next on the LAST step does not wrap or auto-finish (the bond no-ops past the end), so a visible Done/Finish control must call complete().
  • Skip/close (cancel()) ends the tour immediately — the overlay and tooltip disappear, isActive() is false — and fires onCancel.
  • Completing the last step fires onComplete and closes the tour (overlay and tooltip gone, isActive() false).
  • Seen-once: a returning user who completed OR dismissed the tour is not shown it again after reload, while a fresh user is. The package has no built-in "seen" state — the app must persist a flag in onComplete/onCancel and gate start() on it; verify the persistence survives a reload.
  • A step whose target selector matches no element is handled gracefully (the step is skipped or the tour ends) — it never crashes anchoring a tooltip to a null element (the bond keeps target as a plain string and never touches the DOM, so this guard lives in the app's render code).
  • While the tour is active with overlay on (i.e. hasOverlay() is true), the backdrop blocks interaction outside the current step — clicks reach only the tour controls and the highlighted target; ending the tour restores normal interaction. A tour created with overlay: false reports hasOverlay() === false and your render code paints no backdrop. Likewise gate the nav buttons on hasButtons().