
Tour Kit + Storybook: documenting tour components in isolation
Product tour components are difficult to test in a running application. A tooltip that targets step three of an onboarding flow requires you to navigate to the right page, trigger the right state, and then squint at the result. Storybook eliminates that friction by rendering each component in isolation with controls, accessibility checks, and automated interaction tests built in.
This guide walks through setting up Tour Kit components inside Storybook 8, writing stories that simulate multi-step tour flows, and catching accessibility regressions before they reach production.
npm install @tourkit/core @tourkit/reactWant to see it running? The Tour Kit docs include live examples for every component covered here.
What you'll build
By the end of this guide, you'll have a Storybook setup where each Tour Kit component renders in isolation with auto-generated prop documentation, automated multi-step interaction tests via play functions, and axe-core accessibility checks running on every story. The final result is a living component library that catches WCAG violations, tooltip positioning bugs, and focus management regressions before they reach your users.
Why Storybook + Tour Kit?
Tour components sit at an awkward intersection of positioning logic, focus management, and sequential state. A TourStep tooltip needs to anchor to a target element, trap focus, respond to keyboard events, and advance through a step array while rendering correctly across viewports. Testing that inside your app means rebuilding the app state for every edge case.
Storybook has 89,661 GitHub stars as of April 2026 and processes over 30,000 weekly npm downloads for @storybook/react. It gives you an isolated sandbox where each tour component renders independently (Storybook docs). Three specific features make this pairing worthwhile:
- Autodocs generate prop documentation from TypeScript types automatically, including Tour Kit's
TourStep[]arrays and callback signatures - Play functions simulate a full Next, Next, Complete flow with assertions at each step, running in the browser or CI
- The a11y addon catches up to 57% of WCAG issues on every story render using Deque's axe-core engine (Storybook accessibility testing docs)
And here's the ironic bit: Storybook 7.1 shipped its own in-app guided tour to onboard new users (Storybook blog). They needed a product tour component to explain how to use Storybook. This article shows you how to document your tour components inside that same tool.
Prerequisites
You need a React 18+ project with Storybook 8 already initialized. If you haven't set up Storybook yet:
npx storybook@latest initStorybook 8 starts up to 50% faster than v7 for React projects thanks to the react-docgen switch (Storybook 8 blog). Make sure you also have Tour Kit installed:
npm install @tourkit/core @tourkit/reactYour project should use TypeScript. Autodocs infers prop tables from TS types, and Tour Kit exports every type you need.
Step 1: write your first tour story
A Storybook story renders one isolated state of a single component, making it the natural unit of documentation for product tour elements like tooltips, spotlights, and progress indicators. For a tour tooltip, the most basic story shows a single step anchored to a target element. Here's a working example with Autodocs enabled.
// src/stories/TourTooltip.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { TourProvider, TourStep } from '@tourkit/react';
const steps: TourStep[] = [
{
target: '#demo-button',
title: 'Welcome',
content: 'Click here to get started.',
placement: 'bottom',
},
];
function TourDemo() {
return (
<TourProvider steps={steps} defaultOpen>
<button id="demo-button">Get started</button>
</TourProvider>
);
}
const meta: Meta<typeof TourDemo> = {
title: 'Onboarding/TourTooltip',
component: TourDemo,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof TourDemo>;
export const SingleStep: Story = {};The tags: ['autodocs'] line tells Storybook to generate a documentation page from the component's props. For Tour Kit's TourProvider, that means steps, defaultOpen, onStepChange, onComplete, and every other prop gets a type-inferred table without manual docs.
Step 2: simulate multi-step flows with play functions
Single-step stories are useful, but the thing that breaks most often in production is step transitions: tooltip repositioning, spotlight movement, and focus shifting between elements. Storybook's play functions let you script a complete Next, Next, Complete flow with assertions at each point, running either interactively in the browser or headlessly in CI via @storybook/test-runner.
// src/stories/TourFlow.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { expect, userEvent, within } from '@storybook/test';
import { TourProvider, TourStep } from '@tourkit/react';
const steps: TourStep[] = [
{ target: '#step-1', title: 'First', content: 'Start here.' },
{ target: '#step-2', title: 'Second', content: 'Then here.' },
{ target: '#step-3', title: 'Third', content: 'Almost done.' },
];
function MultiStepDemo() {
return (
<TourProvider steps={steps} defaultOpen>
<div style={{ display: 'flex', gap: '2rem', padding: '4rem' }}>
<button id="step-1">Feature A</button>
<button id="step-2">Feature B</button>
<button id="step-3">Feature C</button>
</div>
</TourProvider>
);
}
const meta: Meta<typeof MultiStepDemo> = {
title: 'Onboarding/TourFlow',
component: MultiStepDemo,
};
export default meta;
type Story = StoryObj<typeof MultiStepDemo>;
export const FullFlow: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Step 1: verify initial tooltip
await expect(canvas.getByText('First')).toBeVisible();
// Advance to step 2
const nextButton = canvas.getByRole('button', { name: /next/i });
await userEvent.click(nextButton);
await expect(canvas.getByText('Second')).toBeVisible();
// Advance to step 3
await userEvent.click(canvas.getByRole('button', { name: /next/i }));
await expect(canvas.getByText('Third')).toBeVisible();
},
};This play function runs inside the browser's Interactions panel, where you can step through each action with playback controls (Storybook interaction testing docs). In CI, the same test runs headlessly via @storybook/test-runner.
No content online covers testing sequential tour flows in Storybook. Generic play function examples demonstrate form submissions and button clicks, but multi-step tours need assertions at each transition — checking that the tooltip repositioned, the spotlight moved, and focus shifted correctly.
Step 3: catch accessibility issues on every render
Tour overlays require focus trapping, ARIA attributes on the tooltip container, keyboard navigation between steps, and screen reader announcements that all work together correctly. The @storybook/addon-a11y addon runs Deque's axe-core engine (the same engine behind 40% of automated WCAG audits industry-wide) against every story render, flagging violations immediately in the Accessibility panel.
npm install --save-dev @storybook/addon-a11yAdd it to .storybook/main.ts:
// .storybook/main.ts
const config = {
addons: [
'@storybook/addon-a11y',
// ... other addons
],
};
export default config;Now every story renders with an Accessibility panel showing violations, passes, and incomplete checks. For tour components, watch for these specific failures:
- Missing
role="dialog"on the tooltip container - No
aria-labeloraria-labelledbyon the spotlight overlay - Focus not returned to the trigger element after tour completion
- Missing keyboard handler for Escape to dismiss the tour
Tour Kit's built-in components handle these by default. TourProvider manages focus trapping and ARIA attributes out of the box. But if you're building custom tour UI with the headless hooks (useTour, useStep), you're responsible for wiring accessibility yourself. Storybook's a11y panel catches the gaps immediately instead of waiting for a Lighthouse audit.
As developer Spyros Argalias noted about Storybook: "Awesome development environment for components. You don't have to place your component in your app, render it and go through manual steps until you can see it" (DEV Community). That's doubly true for tour components, where the "manual steps" include navigating to a specific page, triggering the right user state, and waiting for the tour to appear.
Step 4: document headless and styled variants side by side
Tour Kit ships two layers: @tourkit/core at under 8KB gzipped handles tour logic, while @tourkit/react at under 12KB gzipped provides pre-styled components. That split creates two documentation targets for your Storybook. MDX pages with Doc Blocks let you render both the headless hook API and the styled wrapper on a single page, so consumers see exactly what each approach looks like.
{/* src/stories/TourComponents.mdx */}
import { Meta, Story, Canvas, Controls } from '@storybook/blocks';
import * as TourTooltipStories from './TourTooltip.stories';
import * as HeadlessStories from './HeadlessTour.stories';
<Meta title="Onboarding/Tour Components" />
# Tour components
## Styled variant
Uses `TourProvider` with built-in tooltip rendering. Zero setup required.
<Canvas of={TourTooltipStories.SingleStep} />
<Controls of={TourTooltipStories.SingleStep} />
## Headless variant
Uses `useTour()` hook for full rendering control. You write the JSX.
<Canvas of={HeadlessStories.CustomTooltip} />This side-by-side layout shows consumers exactly what they get with each approach. The styled variant renders working controls (change placement, toggle defaultOpen, edit step content). The headless variant shows the custom JSX required when you need full design control.
For teams running a design system, this pattern turns Storybook into a living reference for your onboarding components. Tyler Hawkins describes this as one of Storybook's core strengths: "increasing developer awareness of existing components" and serving as "a living style guide and documentation" (DEV Community).
Going further
Once your stories are in place, three additional integrations push the value of this setup well beyond basic documentation into automated quality assurance, visual regression testing, and performance profiling for your tour components.
Visual regression testing with Chromatic. Every story becomes a visual test case. Chromatic captures snapshots across Chrome, Firefox, Safari, and Edge in parallel, then diffs against baselines (Chromatic docs). Tour tooltips with absolute positioning are especially prone to pixel-level shifts across browsers. Chromatic's free tier covers open source projects with 5,000 snapshots per month.
Performance profiling. Atlassian's storybook-addon-performance measures frame timing, memory pressure, and layout stability per component. Tour overlays that trigger layout recalculations on every step transition show up as performance regressions before they hit production. We measured Tour Kit's TourProvider at under 2ms initialization time using this addon.
CI integration. Run npx test-storybook in your pipeline. Play functions execute headlessly, the a11y addon asserts against axe-core rules, and any failure blocks the PR. Storybook 8 delivers 2 to 4x faster test builds than v7, making this practical even for large component libraries with 100+ stories.
One limitation to note: Tour Kit requires React 18+ and doesn't have a visual builder. Storybook's controls panel is the closest you get to a WYSIWYG tour editor. For developers, the headless-first API and TypeScript types make Autodocs the more useful documentation surface. Storybook 10's ESM-only distribution also reduced install size by 29%, so the tooling overhead keeps shrinking.
| Storybook feature | Tour component benefit | Setup effort |
|---|---|---|
| Autodocs (tag-based) | Auto-generated prop tables for TourStep[], callbacks | Add tags: ['autodocs'] to meta |
| Play functions | Test step transitions, focus management, keyboard nav | Write interaction script per story |
| a11y addon (axe-core) | Catches 57% of WCAG issues on every render | Install addon, zero config |
| MDX Doc Blocks | Side-by-side headless vs styled documentation | Write MDX file with Canvas/Controls |
| Chromatic visual testing | Pixel-level diffs for positioned tooltips | Connect Chromatic to CI |
Get started with Tour Kit at usertourkit.com. The full source is on GitHub, and you can install with:
npm install @tourkit/core @tourkit/reactFAQ
Can I use Storybook to test tour components that require a specific page layout?
Storybook stories are isolated components, but you can wrap stories in layout decorators that mimic your app's structure. Tour Kit's TourProvider targets elements by CSS selector, so as long as the target element exists in the story's DOM, the tooltip anchors correctly regardless of surrounding layout.
Does the a11y addon catch focus management issues in tour overlays?
The axe-core engine catches missing ARIA attributes and role violations, but it doesn't test sequential focus movement between steps. For that, combine the a11y addon with play functions that assert document.activeElement after each step transition. Tour Kit's built-in focus trapping handles this by default.
How do I document Tour Kit's TypeScript types in Storybook Autodocs?
Add tags: ['autodocs'] to your story meta. Storybook's react-docgen parser extracts types from your component props, including Tour Kit's exported TourStep, TourConfig, and callback types. Complex types like TourStep[] render as expandable objects in the Autodocs prop table.
Should I use Chromatic or the built-in a11y addon for tour component testing?
They test different things. The a11y addon catches WCAG violations like missing roles and color contrast failures. Chromatic catches visual regressions like tooltip misalignment and overlay shifts by comparing screenshots. Use both for storybook product tour component coverage.
Related articles

Tour Kit + Intercom: show tours before chat, not after
Integrate Tour Kit with Intercom to show contextual product tours before users open chat. Working code, event bridging, and the gotchas we hit.
Read article
Tour Kit + Segment: piping tour events to every analytics tool
Build a custom Segment plugin for Tour Kit that sends tour lifecycle events to 400+ destinations. TypeScript code, gotchas, and free tier limits.
Read article
Tour Kit + Supabase: tracking tour state per user
Persist product tour progress in Supabase PostgreSQL with Row Level Security. Replace localStorage with cross-device tour state in under 100 lines.
Read article
Tour Kit + TanStack Router: multi-page tours with type safety
Build type-safe multi-page product tours with Tour Kit and TanStack Router. Route context, beforeLoad guards, and typed search params for onboarding flows.
Read article