SpotlightTour
ComponentsProduct toursReact onboarding tours with a tracking spotlight overlay and enterprise a11y
Live demo
Install
$ npm install @usefy/spotlight-tourQuick start
import { SpotlightTour } from "@usefy/spotlight-tour";
function App() {
return (
<>
<YourApp />
<SpotlightTour
defaultOpen
steps={[
// No target → a centered welcome modal.
{ title: "Welcome! 👋", content: "Let's take a quick look around." },
{ target: "#search", title: "Search", content: "Find anything from here." },
{ target: "#settings", content: "Tune your preferences.", placement: "left" },
]}
onFinish={() => console.log("toured!")}
onSkip={(at) => console.log(`dismissed at step ${at}`)}
/>
</>
);
}API reference
<SpotlightTour /> Props
All useSpotlightTour options (steps, open/defaultOpen, step/defaultStep, tourId, keyboard, scrollLock, onFinish, onSkip, …) plus:
| Prop | Type | Default | Description |
|---|---|---|---|
maskColor | string | "rgba(0 0 0 / 0.55)" | Dim overlay color. |
transitionDuration | number | 300 | Spotlight/tooltip transition (ms). 0 disables; forced to 0 under reduced motion. |
overlayClick | "ignore" | "close" | "next" | "ignore" | What a click on the dimmed area does ("close" fires onSkip). Per-step disableOverlayClose downgrades to "ignore". |
zIndex | number | 1000 | z-index of the portal layer. |
labels | Partial<TourLabels> | English | Button/hint label overrides (i18n): back, next, skip, finish, close, gatedHint. |
showProgress / showCounter / showSkip / showClose | boolean | true | Toggle the dots, "2 / 5" counter, Skip button, and close (×). |
renderStep | (ctx) => ReactNode | — | Replace the whole tooltip UI; positioning stays automatic. Spread ctx.tooltipProps for the dialog semantics. |
theme | "light" | "dark" | "system" | "system" | Color theme; "system" follows prefers-color-scheme. |
classNames | SpotlightTourClassNames | — | Per-part class overrides: overlay, spotlight, tooltip, arrow, header, content, footer, dots, counter. |
className | string | — | Extra class on the portal root. |
controllerRef | Ref<TourController> | — | Imperative access: start(at?), next, prev, goTo, skip, finish. |
TourStep
| Field | Type | Default | Description |
|---|---|---|---|
target | string | RefObject | () => Element | null | — | Element to spotlight. Omit for a centered modal step. |
title / content | ReactNode | — | Tooltip heading / body (content required). |
placement | "top" | "bottom" | "left" | "right" | "auto" | "auto" | Preferred tooltip side; "auto" prefers a side that fits, then the roomiest. |
spotlightPadding / spotlightRadius | number | 8 / 8 | Hole padding / corner radius (px). |
missingTarget | "skip" | "wait" | "center" | "skip" | Policy when the target can't be resolved. |
waitTimeout | number | 3000 | How long "wait" holds before skipping (ms). |
advanceOn | { event: "click"; selector?: string } | — | Interaction gate — see the recipe. |
spotlightClicks | boolean | true | Whether clicks pass through the hole to the target. |
scrollIntoView | boolean | true | Auto-scroll an off-screen target into view. |
disableOverlayClose | boolean | false | Make overlayClick behave as "ignore" for this step. |
onEnter / onLeave | () => void | — | Fire when the step settles on screen / is left. |
<SpotlightBeacon /> Props
| Prop | Type | Default | Description |
|---|---|---|---|
target | TourTarget | — | Element the pulsing dot pins to (top-right corner, tracks live). |
onActivate | () => void | — | Called on click — typically controller.current?.start(). |
aria-label | string | "Start tour" | Accessible name of the beacon button. |
className | string | — | Extra class on the beacon button. |
Renders nothing while the target is unresolved or invisible; static (no pulse) under reduced motion.
Go deeper
This page is the quick reference. For every example, prop, and edge case, read the full README — or open Storybook to change props live.