/// Feedback
Tour
A controlled product-tour / coachmark sequence — spotlights each target element and annotates it with a stepped Popover card.
import { Tour } from "@protocore/pds";Basics
Give Tour a steps array — each step points at a target (a ref or CSS selector), a title, and a body. Opening it dims the page, punches a sharp spotlight over the current target, and floats a card beside it with a mono [ 01 / 04 ] index and Back / Next / Done + Skip controls.
Controlled + first-run gating
Drive open and index yourself to resume a half-finished tour, branch steps, or fire the tour once per user. onFinish runs when the last step's Done is pressed; onSkip runs on Skip, Escape, or a scrim click — persist whichever fired so you don't show it again.
When to use it
Reach for a Tour to orient a user *the first time* they land on a dense surface — a new console, a migrated screen, a feature behind a flag. Each step should teach one anchored affordance and then get out of the way.
- Explaining a *single* control in place? Use a HelpTip or Popover — a whole tour is too heavy.
- Showing linear *progress through a task* (not a walkthrough)? Use Steps.
- Something that must block until acknowledged? Use a Dialog.
Keep tours short (three to five steps), let users Skip at any point, and never trap essential information inside one — assume it will be dismissed.
Targeting
A step's target is either a RefObject to a mounted element or a CSS selector string resolved against the document when the step activates. The target is scrolled into view, measured, and re-measured on scroll/resize, so the spotlight and card track the element. If a target can't be found, the card centres itself with no cutout rather than pointing at nothing.
Usage
Do
- Keep tours to three to five anchored, single-idea steps.
- Always leave Skip reachable and honour Escape as skip.
- Persist onFinish/onSkip so a first-run tour shows once.
- Point each step at a stable element — a ref beats a brittle selector.
Don't
- Don't bury required information or the only copy of an action inside a tour.
- Don't chain a dozen steps — split long onboarding into contextual HelpTips.
- Don't target elements that may be unmounted when the step activates.
- Don't run a tour on every visit; gate it on first run.
Accessibility
| Keys | Action |
|---|---|
| Tab / Shift+Tab | Move between the card's controls (focus is trapped in the card). |
| Enter / → | Advance to the next step, or finish on the last step. |
| ← | Return to the previous step. |
| Esc | Skip and dismiss the tour. |
- The card is a modal dialog: focus moves into it on open and is trapped until the tour closes.
- Focus lands on the primary advance button each step so keyboard users can walk the whole tour with Enter.
- The spotlight scrim is decorative (aria-hidden); step content lives in the labelled dialog card.
- The mono step index is presentational — the card exposes its role and label to assistive tech independently.
Tour props
| Prop | Type | Default | Description |
|---|---|---|---|
backLabel | string | Back | Label for the back button. Defaults to `"Back"`. |
className | string | — | Extra class on the card. |
defaultIndex | number | 0 | Initial active step index in uncontrolled mode. Defaults to `0`. |
defaultOpen | boolean | false | Initial open state in uncontrolled mode. Defaults to `false`. |
doneLabel | string | Done | Label for the advance button on the final step. Defaults to `"Done"`. |
index | number | — | Controlled active step index (0-based). Pair with `onIndexChange`. |
nextLabel | string | Next | Label for the advance button on non-final steps. Defaults to `"Next"`. |
onFinish | (() => void) | — | Called when the user completes the final step ("Done"). |
onIndexChange | ((index: number) => void) | — | Called when the active step index changes. |
onOpenChange | ((open: boolean) => void) | — | Called whenever the tour opens or closes. |
onSkip | (() => void) | — | Called when the user dismisses the tour (Skip, Escape, or scrim click). |
open | boolean | — | Controlled open state. Pair with `onOpenChange`. |
skipLabel | string | Skip | Label for the skip control. Defaults to `"Skip"`. |
spotlightPadding | number | 8 | Padding in px around the target inside the spotlight cutout. Defaults to `8`. |
steps * | TourStep[] | — | Ordered steps to walk through. |