WrTour

A guided tour that highlights one element at a time and explains it.

Installation

Import the class, and @use the entry point in your global styles. Nothing warns you when the @use is missing.

import { WrTour } from 'ngwr/tour';

Run a tour

Pass the steps to start(). A step whose target is missing is skipped; Escape ends the tour.

this.tour.start([
  { target: '[data-tour="search"]', title: 'Start here', content: 'Type a name…' },
  { target: '[data-tour="filter"]', content: 'Filters stack.', placement: 'right' },
  { target: '[data-tour="save"]', content: 'Nothing is saved until you press this.', placement: 'top' },
]);

Reading the state

Progress is exposed as signals.

tour.active(); // is a tour running
tour.index(); // 0-based step, -1 when idle
tour.total(); // step count
tour.step(); // the current WrTourStep | null

// Use these, not index() === 0: missing steps are skipped.
tour.isFirst(); // no step before this one
tour.isLast(); // no step after this one

API

NameDescriptionTypeDefault
WrTourInjectable service. No component to place.service—
start(steps)Begin a tour. Restarts if one is running; a no-op under SSR.(steps: readonly WrTourStep[]) => void—
next()Advance. Past the last step it finishes the tour.() => void—
prev()Go back. Stays put on the first step.() => void—
stop()End the tour and return focus where it started.() => void—
activeWhether a tour is running.Signal<boolean>false
index0-based index of the current step, -1 when idle.Signal<number>-1
totalStep count of the running tour.Signal<number>0
isFirstNo step before this one. Use it, not index() === 0, since missing steps are skipped.Signal<boolean>true
isLastNo step after this one; decides between Next and Done.Signal<boolean>false
stepThe step being shown.Signal<WrTourStep | null>null
WrTourStepOne stop on the tour.interface—
targetA CSS selector or the element. A step that matches nothing is skipped.string | HTMLElement—
titleHeading above the copy.string—
contentThe step's body text.string—
placementPreferred side. Falls back to the opposite side near a viewport edge.'top' | 'bottom' | 'left' | 'right''bottom'
panelClassExtra classes on this step's overlay pane.WrClassInput—

CSS variables

Set these on the element itself, with a rule more specific than its Declared on selector. In a global stylesheet, put a class of yours on an ancestor it really has: <body> for an overlay panel, which renders outside your markup. In a component stylesheet the selector alone works, but only for an element in that component's own template. A value on a wrapper or :root is shadowed, because ngwr/tour declares each default on its own element.

VariableDefaultDeclared on
--wr-tour-popup-actions-gapvar(--wr-space-sm).wr-tour-popup
--wr-tour-popup-bordervar(--wr-border-base).wr-tour-popup
--wr-tour-popup-content-font-sizevar(--wr-text-sm).wr-tour-popup
--wr-tour-popup-content-line-heightvar(--wr-leading-normal).wr-tour-popup
--wr-tour-popup-content-margin-bottomvar(--wr-space-lg).wr-tour-popup
--wr-tour-popup-font-familyvar(--wr-font-family-base).wr-tour-popup
--wr-tour-popup-paddingvar(--wr-space-lg).wr-tour-popup
--wr-tour-popup-progress-font-sizevar(--wr-text-xs).wr-tour-popup
--wr-tour-popup-progress-margin-bottomvar(--wr-space-sm).wr-tour-popup
--wr-tour-popup-radiusvar(--wr-border-radius-base).wr-tour-popup
--wr-tour-popup-title-font-sizevar(--wr-text-base).wr-tour-popup
--wr-tour-popup-title-font-weightvar(--wr-font-weight-semibold).wr-tour-popup
--wr-tour-popup-title-margin-bottomvar(--wr-space-sm).wr-tour-popup
--wr-tour-spotlight-radiusvar(--wr-border-radius-base).wr-tour__spotlight

Dependencies

Angular CDKa11y, overlay, portal
Built onButton, Overlay

See also