JavaScript Product Tour & Onboarding Library – GlowTour.js

Category: Javascript , Recommended | September 15, 2026
AuthorGlowhop
Last UpdateSeptember 15, 2026
LicenseMIT
Tags
Views0 views
JavaScript Product Tour & Onboarding Library – GlowTour.js

GlowTour.js is a TypeScript product-tour library for onboarding walkthroughs and feature guidance in vanilla JavaScript, React, Vue, Solid, and Angular.

Features

  • CSS selectors, DOM elements, and resolver functions for step targets.
  • Async workflow actions for application state, DOM availability, and user events.
  • Ordered popover and pointer placement with collision fallback.
  • Configurable scrolling, page interaction, overlays, and missing-target handling.
  • Dialog semantics, keyboard shortcuts, focus trapping, and focus restoration.
  • Light and dark themes controlled through CSS custom properties.
  • Programmatic navigation, state subscriptions, and lifecycle analytics.
  • Optional JSON configuration for CMS or API-driven workflows.

How To Use GlowTour.js

Installation (Vanilla JS)

Install the Vanilla adapter and default theme:

npm i @glowhop/vanilla-tour @glowhop/styles-tour

Import the stylesheet and Vanilla API. The regular entry point requires one call to registerGlowTourElements(). Import from @glowhop/vanilla-tour/auto when automatic Custom Element registration is preferable

import "@glowhop/styles-tour/default.css";
import {
  createDefaultTourElement,
  createGlowTour,
  registerGlowTourElements,
} from "@glowhop/vanilla-tour";

Basic Usage

Create the elements that the tour will highlight:

<label>
  Workspace name
  <input id="workspace-name" value="Design Team" />
</label>
<button id="save-settings" type="button">Save settings</button>
<button id="start-tour" type="button">Start tour</button>

Create one controller, build the workflow, mount the default tour element, and connect the start button:

import "@glowhop/styles-tour/default.css";
import {
  createDefaultTourElement,
  createGlowTour,
  registerGlowTourElements,
} from "@glowhop/vanilla-tour";
registerGlowTourElements();
const tour = createGlowTour();
const workflow = tour
  .create("workspace-onboarding")
  .step({
    id: "workspace-name",
    target: "#workspace-name",
    title: "Name your workspace",
    content: "Choose the name shown across the workspace.",
  })
  .step({
    id: "save-settings",
    target: "#save-settings",
    title: "Save your settings",
    content: "Save the current workspace configuration.",
  })
  .build();
document.body.append(createDefaultTourElement(tour));
document.querySelector("#start-tour").addEventListener("click", () => {
  void tour.run(workflow);
});

Direct Browser Setup With CDN

Load the Vanilla JavaScript and default CSS packages from a CDN:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@glowhop/styles-tour/default.css"
/>
<script type="module">
  import {
    createDefaultTourElement,
    createGlowTour,
    registerGlowTourElements,
  } from "https://cdn.jsdelivr.net/npm/@glowhop/vanilla-tour/+esm";
  registerGlowTourElements();
  const tour = createGlowTour();
  const workflow = tour
    .create("feature-tour")
    .step({
      id: "feature",
      target: "#feature",
      title: "Feature controls",
      content: "Use these controls to configure the feature.",
    })
    .build();
  document.body.append(createDefaultTourElement(tour));
  document.querySelector("#start-tour").addEventListener("click", () => {
    void tour.run(workflow);
  });
</script>

Wait For UI State Or User Actions

A workflow can pause until an element appears or respond to an event from the active element.

const workflow = tour
  .create("editor-tour")
  .step({
    id: "open-preview",
    target: "#preview-button",
    title: "Open the preview",
    content: "Select Preview to continue.",
    behavior: {
      allowInteraction: true,
    },
  })
  .onTargetEvent("click", (_event, context) => {
    context.advance();
  })
  .waitUntilElement("#preview-panel", {
    timeout: 5000,
  })
  .step({
    id: "preview-panel",
    target: "#preview-panel",
    title: "Preview panel",
    content: "Review the rendered result here.",
  })
  .build();

Rich Content In Vanilla Tours

Vanilla title and content values accept a string or DOM Node. Strings render as text. Create a DOM node for images, videos, or custom markup.

Sanitize untrusted CMS or API content before constructing rich DOM content.

const preview = document.createElement("img");
preview.src = "/images/editor-preview.png";
preview.alt = "Editor preview";
preview.width = 280;
const workflow = tour
  .create("media-tour")
  .step({
    id: "preview",
    target: "#preview-button",
    title: "Preview",
    content: preview,
  })
  .build();

Workflow Builder API

Create a workflow with tour.create(), chain steps and actions, and finish with .build().

  • tour.create(name, options?): Creates a workflow builder. name is the workflow identifier and options accepts the Start Options listed later.
  • .step(params): Defines a tour step and returns a WorkflowStepBuilder.
  • .do(callback): Runs a synchronous or async action between steps. Returning false stops the rest of that step action sequence.
  • .wait(ms): Pauses for a fixed number of milliseconds.
  • .waitUntil(fn, options?): Polls a condition until it returns true or the timeout expires.
  • .waitUntilElement(selector, options?): Waits for a matching element to enter the DOM.
  • .onTargetEvent(event, callback): Listens for one DOM event, an array of events, or a custom event on the current step element.
  • .build(): Returns an immutable WorkflowDefinition.

Step-level transition callbacks belong inside .step():

  • beforeAdvance(context): Runs before the workflow advances and can return a promise.
  • beforeCancel(context): Runs before cancellation and can return a promise.
  • beforePrevious(context): Runs before navigation to the previous step and can return a promise.

Step Parameters

Every step requires id, target, title, and content.

  • id (string, required): Stable unique identifier inside the workflow. Duplicate IDs fail validation during .build().
  • target (string | HTMLElement | TargetResolver, required): CSS selector, DOM element, or resolver function.
  • title (string | Node in Vanilla, required): Popover title.
  • content (string | Node in Vanilla, required): Popover content.
  • resetPropsOnEnter (boolean, default true): Resets step properties when the step becomes active.
  • data (Record, optional): Custom data attached to the step.
  • overlay (OverlayOptions, optional): Step-specific overlay settings.
  • popover (PopoverOptions, optional): Step-specific popover settings.
  • indicator (IndicatorOptions, optional): Step-specific pointer settings.
  • behavior (StepBehavior, optional): Interaction, scrolling, and missing-element settings.
  • beforeAdvance (callback, optional): Runs before advancing.
  • beforeCancel (callback, optional): Runs before cancellation.
  • beforePrevious (callback, optional): Runs before going back.

Configuration Reference

Start Options

Pass these options to tour.create(name, options).

  • cancellable (boolean, default true): Controls user cancellation.
  • animated (boolean, default true): Controls animations. Reduced-motion preferences disable them automatically.
  • overlay (OverlayOptions): Workflow-level overlay settings.
  • popover (PopoverOptions): Workflow-level popover settings.
  • indicator (IndicatorOptions): Workflow-level pointer settings.
  • behavior (StepBehavior): Workflow-level behavior settings.
  • allowScroll (boolean, default true): Keeps page scrolling available during the tour. Set false to lock it until finish, cancel, error, or disposal.
  • onStart ((context) => void | Promise<void>): Lifecycle hook called when the tour starts.
  • onCancel ((context) => void | Promise<void>): Lifecycle hook called during cancellation.
  • onFinish ((context) => void | Promise<void>): Lifecycle hook called during completion.
  • onEvent ((event: TourEvent) => void): Monitoring callback for this workflow.

Overlay Options

  • color (string): Overlay color. The theme fill is used when omitted.
  • opacity (number, default 0.7): Overlay opacity from 0 to 1.
  • padding (number, default 8): Space around the highlighted element in pixels.
  • radius (number, default 8): Cutout radius in pixels.
  • animated (boolean, default true): Controls overlay animation.
  • animation (AnimationOptions): Custom duration and easing.

Popover Options

Valid popover placements are top, bottom, left, and right. GlowTour.js checks placementTryOrder in sequence and centers the popover when none of the listed sides has enough viewport space.

  • placementTryOrder (Array, default ["bottom", "top", "right", "left"]): Ordered popover placement preferences.
  • gap (number, default 16): Space between the popover and highlighted element plus the minimum viewport edge gap, in pixels.
  • hideFooter (boolean, default false): Hides the footer navigation controls.
  • hideAdvanceButton (boolean, default false): Hides the Next button. Keyboard advance remains available.
  • disableAdvanceButton (boolean, default false): Blocks button and keyboard advance.
  • hidePreviousButton (boolean, default false): Hides the Previous button. Keyboard navigation remains available.
  • disablePreviousButton (boolean, default false): Blocks button and keyboard navigation to the previous step.
  • animated (boolean, default true): Controls popover animation.
  • animation (AnimationOptions): Custom duration and easing.
  • keyboardShortcuts.advance (string[], default ["Enter", "ArrowRight"]): Advance shortcuts.
  • keyboardShortcuts.previous (string[], default ["ArrowLeft", "Backspace"]): Previous-step shortcuts.
  • keyboardShortcuts.cancel (string[], default ["Escape"]): Cancel shortcuts.
  • arrow (PopoverArrowOptions): Popover arrow settings.

Popover Arrow Options

JavaScript arrow values are written as inline CSS custom properties and take precedence over corresponding --glow-tour-arrow-* values in a stylesheet.

  • disabled (boolean, default false): Hides the popover arrow.
  • color (string): Arrow fill. The theme surface color is used when omitted.
  • size (number, default 12): Arrow width and height in pixels before rotation.
  • borderWidth (number, default 1): Arrow border width in pixels.
  • borderRadius (number, default 0): Arrow border radius in pixels.
  • edgePadding (number, default 16): Minimum distance from the popover edges in pixels.
  • styleNonce (string): CSP nonce for injected arrow styles.
  • disableAutoStyles (boolean, default false): Disables built-in arrow style injection for a custom arrow shape.

Indicator Options

  • disabled (boolean, default false): Hides the decorative pointer.
  • gap (number, default 16): Space between the pointer and highlighted element in pixels.
  • placementTryOrder (Array, default ["left", "right", "top", "bottom"]): Ordered pointer placement preferences.
  • animated (boolean, default true): Controls pointer animation.
  • animation (AnimationOptions): Custom duration and easing.

Behavior Options

  • allowInteraction (boolean, default false): Permits interaction with the highlighted element.
  • disableAutoFocus (boolean, default false): Skips automatic focus handling.
  • disableAutoScroll (boolean, default false): Stops automatic scrolling to an off-screen element.
  • missingTargetStrategy ("error" | "wait" | "skip", default "error"): Selects the response when the element cannot be resolved.
  • overlayClick ("none" | "advance" | "cancel", default "none"): Selects the action for a click on the dimmed overlay.
  • targetTimeout (number, default 3000): Maximum wait time in milliseconds.
  • scroll (ScrollOptions): Scroll alignment and animation settings.

Scroll Options

  • behavior ("auto" | "smooth", default "smooth"): Browser scroll behavior. Reduced-motion mode uses an instant scroll.
  • block ("start" | "center" | "end" | "nearest", default "center"): Vertical alignment.
  • inline ("start" | "center" | "end" | "nearest", default "nearest"): Horizontal alignment.

Animation Options

  • duration (number, default 180): Animation time in milliseconds.
  • easing (string, default "ease-out"): CSS easing function.

Animations use a zero duration when animation is disabled or reduced motion is detected.

Wait Options

These options apply to .waitUntil() and .waitUntilElement().

  • interval (number, default 16): Poll interval in milliseconds.
  • timeout (number, default 3000): Maximum wait time in milliseconds.

Programmatic Control

createGlowTour() accepts two controller-level options:

  • onSubscriberError: Receives errors thrown by state or step subscribers.
  • onEvent: Receives monitoring events for every workflow run by this controller.

The returned controller exposes these methods:

tour.create(name, options?);
tour.run(workflow, options?);
tour.advance();
tour.previous();
tour.goToStep(index);
tour.cancel();
tour.dispose();
  • tour.create(name, options?) returns a workflow builder.
  • tour.run(workflow, { startAt? }) runs a built workflow and returns a promise. startAt accepts a stable step ID.
  • tour.advance() moves forward when canAdvance is true.
  • tour.previous() moves backward when canPrevious is true.
  • tour.goToStep(index) jumps to a zero-based step index.
  • tour.cancel() cancels the tour when canCancel is true.
  • tour.dispose() cancels pending work, releases the connected root, and permanently disposes that controller instance.

Tour State

Read a snapshot with tour.state.get() or subscribe with tour.state.subscribe(listener). The subscription method returns an unsubscribe function.

{
  status: "idle" | "starting" | "transitioning" | "active" |
          "finished" | "cancelled" | "error" | "disposed",
  name: string,
  totalSteps: number,
  currentStepIndex: number,
  currentStep: TourCurrentStep | null,
  direction: "advance" | "previous",
  canAdvance: boolean,
  canPrevious: boolean,
  canCancel: boolean,
  isFirstStep: boolean,
  isLastStep: boolean,
  error: Error | null
}

Monitor Tour Events

Use onEvent to send tour activity to analytics or logging code:

const tour = createGlowTour({
  onEvent(event) {
    analytics.track(event.type, {
      workflow: event.workflowName,
      step: event.stepId,
      source: event.source,
      duration: event.durationMs,
    });
  },
});

Event Types

  • tour:start: Emitted after onStart completes and before the first step appears.
  • step:enter: Emitted when a step is on screen and interactive.
  • step:leave: Emitted when the workflow leaves a step.
  • tour:complete: Emitted after the workflow passes its final step.
  • tour:cancel: Emitted when the tour is cancelled.
  • tour:error: Emitted when the tour fails.

Event Payload

Every monitoring event includes:

  • type: Event type.
  • workflowName: Workflow name passed to create().
  • stepId: Related step ID, or null.
  • stepIndex: Zero-based step index, or -1 when no step applies.
  • stepCount: Total number of workflow steps.
  • direction: "advance" or "previous".
  • source: Source of the transition.
  • timestamp: Date.now() value at emission.
  • durationMs: Duration associated with the event.
  • error: Failure object on tour:error only.

Resume A Tour

GlowTour.js does not include a persistence layer. Store a stable step ID in sessionStorage, localStorage, or application storage, rebuild the workflow after a reload, and pass the ID through startAt.

const savedStepId = sessionStorage.getItem("onboarding-step");
await tour.run(workflow, {
  startAt: savedStepId || undefined,
});

JSON Configuration

Import the config entry point when workflows come from a CMS, API, or stored JSON object.

Use the existing mounted tour controller from the Vanilla setup:

import {
  ConfigValidationError,
  createWorkflowFromConfig,
} from "@glowhop/vanilla-tour/config";
const config = {
  name: "onboarding",
  overlay: { opacity: 0.55 },
  steps: [
    {
      id: "invite-button",
      target: "#invite-button",
      title: "Invite your team",
      content: "Open the invite form.",
      actions: [
        {
          type: "waitUntilElement",
          selector: "#invite-button",
          timeout: 5000,
        },
      ],
      eventHandlers: [
        {
          event: "click",
          action: { type: "focusTarget" },
        },
      ],
    },
  ],
};
try {
  const workflow = createWorkflowFromConfig(config);
  await tour.run(workflow);
} catch (error) {
  if (error instanceof ConfigValidationError) {
    console.error(error.issues);
  }
}

JSON Configuration Rules

  • name and steps are required.
  • Each step requires id, target, title, and content.
  • JSON targets use CSS selectors.
  • JSON title and content values use strings.
  • Global and per-step overlay, popover, indicator, and behavior fields use the Builder option names.
  • data stores JSON-compatible step metadata.
  • actions runs actions associated with a step.
  • eventHandlers attaches a configured action to an event.

Built-in JSON Actions

  • wait with ms maps to a fixed delay.
  • waitUntilElement accepts selector, plus optional interval and timeout.
  • clickTarget dispatches a click to the active element.
  • focusTarget moves focus to the active element.

Same-runtime JavaScript configuration objects can also use functions in actions and eventHandlers. advanceAction, previousAction, cancelAction, onStart, onCancel, and onFinish accept functions only and cannot be represented in transported JSON.

Pass validateContent to createWorkflowFromConfig() when an application-created configuration object needs framework content such as a DOM Node, React node, Vue VNode, or Angular TemplateRef. Keep the default string validation for untrusted JSON.

Each adapter exports its own config entry point:

@glowhop/react-tour/config
@glowhop/vue-tour/config
@glowhop/solid-tour/config
@glowhop/angular-tour/config
@glowhop/vanilla-tour/config

Styling And Theming

Import @glowhop/styles-tour/default.css before overriding the theme tokens. The default stylesheet declares its tokens at zero specificity, which permits overrides on :root, the tour root, or an ancestor of the tour.

-where([data-glow-tour-root]) {
  --glow-tour-color-accent: #7c3aed;
  --glow-tour-color-surface: #faf5ff;
  --glow-tour-color-text: #24143f;
  --glow-tour-radius: 14px;
  --glow-tour-popover-width: 320px;
}

The default theme follows prefers-color-scheme. Set data-glow-tour-theme="light" or data-glow-tour-theme="dark" on an ancestor to force a palette.

Color Tokens

  • --glow-tour-color-accent: #4c35fd light, #6d5bff dark.
  • --glow-tour-color-accent-hover: #3f2be0 light, #5d4bf0 dark.
  • --glow-tour-color-accent-active: #3522c7 light, #4f3ce0 dark.
  • --glow-tour-color-on-accent: #ffffff.
  • --glow-tour-color-surface: #ffffff light, #1c1c21 dark.
  • --glow-tour-color-surface-muted: #f6f6f7 light, #26262d dark.
  • --glow-tour-color-text: #1f1f23 light, #f2f2f4 dark.
  • --glow-tour-color-text-muted: #5f5f66 light, #a8a8b3 dark.
  • --glow-tour-color-border: #dedee3 light, #3a3a44 dark.
  • --glow-tour-overlay-color: #000000 in both palettes.

Spacing And Size Tokens

  • --glow-tour-spacing: 8px.
  • --glow-tour-popover-width: 352px.
  • --glow-tour-control-height: 32px.
  • --glow-tour-viewport-gap: 16px.

Style Tokens

  • --glow-tour-radius: 8px.
  • --glow-tour-shadow: 0 4px 12px rgb(0 0 0 / 8%) in light mode and 0 8px 24px rgb(0 0 0 / 56%) in dark mode.
  • --glow-tour-transition-duration: 120ms.
  • --glow-tour-transition-easing: ease-out.

Arrow Tokens

The core injects the arrow rules. These variables work even when the default theme stylesheet is absent.

  • --glow-tour-arrow-color: Uses --glow-tour-color-surface, with #ffffff as fallback.
  • --glow-tour-arrow-border-color: Uses --glow-tour-color-border, with #dedee3 as fallback.
  • --glow-tour-arrow-border-width: 1px.
  • --glow-tour-arrow-border-radius: 0px.
  • --glow-tour-arrow-size: 12px.

Vanilla Adapter Functions

  • createGlowTour(options?: GlowTourOptions): VanillaGlowTour: Creates the tour controller.
  • registerGlowTourElements(): void: Registers the GlowTour Custom Elements.
  • createDefaultTourElement(tour, options?): GlowTourRootElement: Creates the default overlay, popover, pointer, and navigation composition.

Vanilla Custom Elements Reference

createDefaultTourElement(tour) creates the normal composition. Compose the elements manually when the popover structure itself needs to change.

  • glow-tour-root: Root container. Public property: tour: VanillaGlowTour.
  • glow-tour-overlay: Backdrop and highlighted cutout layer.
  • glow-tour-popover: Dialog container for the current step.
  • glow-tour-header: Renders the step title.
  • glow-tour-content: Renders the step content.
  • glow-tour-footer: Contains navigation controls.
  • glow-tour-pointer: Decorative directional pointer. Public property: directionContent: PointerDirectionContent.
  • glow-tour-advance-trigger: Next control. Public property: disabled: boolean.
  • glow-tour-cancel-trigger: Cancel control. Public property: disabled: boolean.
  • glow-tour-back-trigger: Previous control. Public property: disabled: boolean.

GLOW_TOUR_ELEMENT_NAMES contains all ten registered element names.

The pointer’s default directional glyphs are 👆 for top, 👇 for bottom, 👈 for left, and 👉 for right. Assign strings or DOM nodes through directionContent to replace them.

Framework And Browser Compatibility

GlowTour.js currently lists these framework contracts:

  • Vanilla/Browser: Custom Elements and Shadow DOM. Chrome 77+, Firefox 63+, Safari 13+, and Edge 79+.
  • React: React 18 and 19 through @glowhop/react-tour.
  • Vue: Vue 3.3+ through @glowhop/vue-tour.
  • Solid: Solid 1.8+ through @glowhop/solid-tour.
  • Angular: Angular 18+ through @glowhop/angular-tour.

Alternatives & Related Resources

You Might Be Interested In:


Leave a Reply