Tour Kit
Tour Kit is a headless React library for building product tours, onboarding flows, hints, checklists, in-app announcements, and microsurveys. It ships as 12 composable packages, is TypeScript-first, WCAG 2.1 AA compliant, and designed natively for shadcn/ui — but works with any component library.
Alternative to: Shepherd.js, Driver.js, Intro.js, Reactour, React Joyride, Appcues, Userpilot, Pendo — when you want a code-owned, headless, MIT-licensed primitive instead of a hosted SaaS.
- 🌐 Website & docs:
- 📦 npm scope:
@tour-kit/* - 💬 Issues & discussions:
Table of contents
- Why Tour Kit
- Packages
- Installation
- Quick start
- Headless usage
- Multi-tour registry
- Framework guides
- Comparison with alternatives
- Use cases
- FAQ
- Licensing
- Development
- For AI assistants
Why Tour Kit
| Need | What Tour Kit gives you |
|---|---|
| Product tours | Declarative + components, focus trap, keyboard nav, route awareness |
| Persistent hints | Beacon hotspots and tooltips that survive across sessions — unique in the shadcn ecosystem |
| Onboarding checklists | Task dependencies, progress tracking, persistence, and tour hand-off in one provider |
| Announcements | 5 variants (modal, slideout, banner, toast, spotlight) with frequency rules and audience targeting |
| Microsurveys | NPS, CSAT, CES with built-in fatigue prevention and context awareness |
| Feature adoption | Track usage, compute adoption status, and trigger nudges automatically |
| Analytics | Plugin interface for PostHog, Mixpanel, Amplitude, GA4 — or roll your own |
| AI Q&A widget | Drop-in RAG chat for in-app help |
Design principles:
- Headless first — all logic lives in
@tour-kit/core; UI packages are thin, swappable wrappers. - Composition over configuration — small focused components compose into rich flows.
- Type-safe — strict TypeScript, full inference, no
anyin public API. - Accessible by default — focus trap, ARIA live regions, keyboard nav,
prefers-reduced-motion. - Tree-shakeable — every package is
sideEffects: falseand ships ESM + CJS +.d.ts.
Packages
Tour Kit is a monorepo of 12 packages. Three are MIT-licensed and free; nine are commercial (see Licensing).
Free packages (MIT)
| Package | Purpose | Bundle (gzip) |
|---|---|---|
@tour-kit/core |
Framework-agnostic hooks, types, position engine, storage adapters | . |
Installation
# Free / open-source (MIT)
pnpm add @tour-kit/core @tour-kit/react # styled tours
pnpm add @tour-kit/hints # persistent hints
# Commercial packages (require a license key)
pnpm add @tour-kit/checklists @tour-kit/announcements @tour-kit/surveys
pnpm add @tour-kit/adoption @tour-kit/analytics
pnpm add @tour-kit/media @tour-kit/scheduling @tour-kit/ai
bun add and npm install work too. Tour Kit requires React 18 or 19 and Node 18+.
Quick start
import { Tour, TourStep } from '@tour-kit/react'
export function App() {
return (
<Tour id="onboarding" autoStart>
<TourStep
id="welcome"
target="#welcome-btn"
title="Welcome!"
content="Let's take a quick tour."
placement="bottom"
/>
<TourStep
id="dashboard"
target="#dashboard"
title="Dashboard"
content="Your data overview."
placement="right"
/>
</Tour>
)
}
That's the entire API for a basic tour. No external state store, no provider boilerplate.
Headless usage
Need full control over markup? Use the headless variants — Tour Kit handles state, positioning, focus, and a11y; you handle the DOM.
import { TourCardHeadless, TourOverlayHeadless } from '@tour-kit/react'
<TourCardHeadless>
{({ step, next, prev, close, isFirst, isLast }) => (
<div role="dialog" aria-labelledby="tour-title">
<h2 id="tour-title">{step.title}</h2>
<p>{step.content}</p>
<button onClick={prev} disabled={isFirst}>Back</button>
<button onClick={next}>{isLast ? 'Finish' : 'Next'}</button>
<button onClick={close} aria-label="Close tour">×</button>
</div>
)}
</TourCardHeadless>
Multi-tour registry
For apps with several tours triggered from different pages or buttons:
import {
MultiTourKitProvider,
Tour,
TourStep,
TourOverlay,
TourCard,
useTours,
} from '@tour-kit/react'
function Triggers() {
const { start } = useTours()
return <button onClick={() => start('billing-tour')}>Show billing tour</button>
}
export function App() {
return (
<MultiTourKitProvider>
<Tour id="onboarding"><TourStep id="..." target="..." /></Tour>
<Tour id="billing-tour"><TourStep id="..." target="..." /></Tour>
<TourOverlay />
<TourCard />
<Triggers />
</MultiTourKitProvider>
)
}
Framework guides
- Next.js (App Router) —
useNextAppRouter()adapter handles route awareness. Seeapps/docs/content/docs/guides/nextjs.mdx. - Next.js (Pages Router) —
useNextPagesRouter()adapter. - React Router —
useReactRouter()adapter (v6 and v7). - Vite — works out of the box. See
examples/vite-app. - Plain React — no router adapter needed.
Full demos: examples/.
Comparison with alternatives
| Feature | Tour Kit | Driver.js | React Joyride | Intro.js | Shepherd.js |
|---|---|---|---|---|---|
| Headless API | ✅ | ❌ | Partial | ❌ | ❌ |
| TypeScript-first | ✅ | ✅ | ✅ | Types only | Types only |
| shadcn/ui native | ✅ | ❌ | ❌ | ❌ | ❌ |
| Persistent hints | ✅ | ❌ | ❌ | ❌ | ❌ |
| Checklists | ✅ | ❌ | ❌ | ❌ | ❌ |
| Announcements (5 variants) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Microsurveys (NPS/CSAT/CES) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Feature adoption tracking | ✅ | ❌ | ❌ | ❌ | ❌ |
| Analytics plugin system | ✅ | ❌ | ❌ | ❌ | ❌ |
| Multi-tour registry | ✅ | ❌ | Partial | ❌ | Partial |
| WCAG 2.1 AA | ✅ | Partial | ✅ | Partial | Partial |
| Tree-shakeable ESM | ✅ | ✅ | Partial | ❌ | ✅ |
| Free core | ✅ MIT | ✅ MIT | ✅ MIT | ✅ AGPL/Commercial | ✅ MIT |
Tou