# @inklu/tour > Accessible, headless product tours for React: a spotlight overlay, resilient target tracking and full control over the card. - Install: `npm install @inklu/tour` - Agent skill: `npx skills add nkurunziza-saddy/inklu --skill inklu-tour` ## Docs - [Full reference](https://inklu.saddy.me/tour/llms-full.txt): every export, option and pattern, as Markdown - [Documentation](https://inklu.saddy.me/tour): Defining tours, targeting steps and the API ## Optional - [Source](https://github.com/nkurunziza-saddy/inklu/tree/main/packages/tour) - [npm](https://www.npmjs.com/package/@inklu/tour) ## Setup prompt Set up an accessible product tour using the `@inklu/tour` package. Do not invent APIs. If something here is ambiguous, read https://inklu.saddy.me/tour before guessing. ### 1. Install `npm install @inklu/tour` Peers: `react` and `react-dom` 18 or 19. ### 2. Define your tours Create a `TourConfig[]` array. Each config has an `id` and a `steps` array. ```tsx import { type TourConfig, TourProvider, useTour } from "@inklu/tour"; const tours: TourConfig[] = [ { id: "onboarding-tour", steps: [ { id: "step-welcome", target: "#welcome-header", placement: "bottom", meta: { title: "Welcome aboard!", content: "Let's take a quick tour around the dashboard.", }, }, ], }, ]; ``` ### 3. Add the provider Wrap your app (or the subtree that contains tour targets) with `TourProvider`: ```tsx // app/providers.tsx — must be a Client Component "use client"; import { TourProvider, type TourConfig } from "@inklu/tour"; import { useRouter } from "next/navigation"; const tours: TourConfig[] = [/* ... */]; export function Providers({ children }: { children: React.ReactNode }) { const router = useRouter(); return ( router.push(route)}> {children} ); } ``` `onNavigate` is required for cross-page tours. ### 4. Trigger a tour Call `startTour` from the `useTour` hook anywhere inside the provider: ```tsx "use client"; import { useTour } from "@inklu/tour"; export function StartButton() { const { startTour } = useTour(); return ; } ``` ### 5. Target elements Prefer `data-tour-step` attributes over CSS selectors — they survive refactors: ```tsx ``` For async-loaded elements, use a target object with a timeout and strategy: ```tsx target: { selector: ".async-loaded-modal", timeout: 3000, strategy: "skip" } ``` ### 6. Composition (optional) Replace the default card UI with `TourRoot` + primitives from `@inklu/tour`: `TourSpotlight`, `TourCard`, `TourArrow`, `TourNextButton`, `TourPreviousButton`, `TourCloseButton`, `useTourContext`. Always wire `labelId` and `descriptionId` from `useTourContext` to the corresponding elements in your card to maintain accessibility. ### Constraints - Never put `TourProvider` in a Server Component file. - Do not use dot notation like `` — import sub-components explicitly. - The `useTour` hook throws if called outside a `TourProvider`. ### Before you finish Confirm every `target` selector or `data-tour-step` value resolves to a real element, and that the tour `id` passed to `startTour` matches a config id.