Overlay
Tour
Guided product tour: a full-screen overlay with a spotlight cut out around the current target element and a positioned tooltip with Back/Next/Skip controls. Steps whose target cannot be found are skipped automatically.
Import
import { Tour } from "@zephora/react";Examples
Basic tour
Three steps pointing at in-page elements (refs or CSS selectors). Next/Back move through the steps, Skip or Escape ends the tour early.
Search
Compose
Settings
const searchRef = React.useRef<HTMLDivElement>(null);
const composeRef = React.useRef<HTMLDivElement>(null);
const settingsRef = React.useRef<HTMLDivElement>(null);
const [open, setOpen] = React.useState(false);
const steps: TourStep[] = [
{ target: searchRef, title: "Search", content: "Find anything from one box." },
{ target: composeRef, title: "Compose", content: "Start a new draft here." },
{ target: settingsRef, title: "Settings", content: "Tune themes and alerts.", placement: "top" },
];
<Button onClick={() => setOpen(true)}>Start tour</Button>
<div ref={searchRef}>Search</div>
<div ref={composeRef}>Compose</div>
<div ref={settingsRef}>Settings</div>
<Tour steps={steps} open={open} onOpenChange={setOpen} />Controlled step
`stepIndex` + `onStepIndexChange` put the active step in your state, so the tour can start at any step and report progress.
Filters
Export
Last viewed step: 1
const [open, setOpen] = React.useState(false);
const [stepIndex, setStepIndex] = React.useState(0);
<Button onClick={() => { setStepIndex(0); setOpen(true); }}>From the start</Button>
<Button onClick={() => { setStepIndex(1); setOpen(true); }}>Jump to step 2</Button>
<p>Last viewed step: {stepIndex + 1}</p>
<Tour
steps={steps}
open={open}
onOpenChange={setOpen}
stepIndex={stepIndex}
onStepIndexChange={setStepIndex}
/>API
Tour props
| Prop | Type | Default | Description |
|---|---|---|---|
steps * | TourStep[] | — | Ordered tour steps. Steps whose target cannot be found are skipped. |
open | boolean | — | Controlled open state. |
defaultOpen | boolean | false | Initial open state (uncontrolled). |
onOpenChange | (open: boolean) => void | — | Called whenever the tour requests an open state change. |
stepIndex | number | — | Controlled active step index. |
defaultStepIndex | number | 0 | Initial step for uncontrolled usage. |
onStepIndexChange | (index: number) => void | — | Fires whenever the active step changes. |
onFinish | () => void | — | Called when the user completes the last step. |
onSkip | () => void | — | Called when the user skips out of the tour (Skip button or Escape). |
spotlightPadding | number | 8 | Space between the target and the spotlight cut-out, in px. |
scrollIntoView | boolean | true | Scrolls the target into view when a step activates. |
classNames | Partial<Record<TourSlot, string>> | — | Per-slot class overrides: "overlay" | "spotlight" | "tooltip" | "title" | "content" | "footer" | "button" | "progress". Appended after the module classes and also applied in unstyled mode. |
unstyled | boolean | false | Headless mode — skips Zephora styling. |
TourStep props
| Prop | Type | Default | Description |
|---|---|---|---|
target * | string | RefObject<HTMLElement | null> | — | CSS selector or ref pointing at the element to highlight. |
title | ReactNode | — | Optional step heading. |
content * | ReactNode | — | Step body content. |
placement | "top" | "bottom" | "left" | "right" | "bottom" | Preferred tooltip side (flips when there is no room). |
Keyboard
| Key | Action |
|---|---|
ArrowRight | Next step (finishes the tour on the last step). |
ArrowLeft | Previous step. |
Escape | Skips out of the tour (fires onSkip). |
Tab / Shift+Tab | Cycles focus inside the tooltip — focus is trapped while open. |