Skip to main content

Headless onboarding: what it means, why it matters, and how to start

What headless onboarding is, why it beats styled tour libraries for design system teams, and how to implement it with code examples.

DomiDex
DomiDexCreator of Tour Kit
April 12, 202615 min read
Share
Headless onboarding: what it means, why it matters, and how to start

Headless onboarding: what it means, why it matters, and how to start

Your team spent months building a design system. Custom tokens, consistent spacing, a Tailwind config that enforces your brand across every component. Then someone drops in a product tour library and suddenly there's a tooltip on screen that looks like it was teleported from a different app.

That's the headless onboarding problem. And it explains why the pattern is growing faster than any other approach to in-app guidance.

npm install @tourkit/core @tourkit/react

This guide covers the full picture: what headless onboarding actually means, how the architecture works, when you should (and shouldn't) adopt it, which tools exist, and how to get started. We built Tour Kit as a headless onboarding library, so we'll use it for examples. The concepts apply to any headless approach.

What is headless onboarding?

Headless onboarding is a pattern where the tour library handles behavior (step sequencing, element targeting, scroll management, keyboard navigation, persistence, analytics) without rendering any UI. You bring every visual element. The tooltip, the spotlight overlay, the progress bar, the dismiss button. All yours. The library provides the logic through hooks and context providers, and you wire it into your existing component system.

Martin Fowler describes the broader headless component pattern as extracting "all non-visual logic and state management, separating the brain of a component from its looks" (martinfowler.com). Applied to onboarding, this means your product tours look identical to the rest of your app because they're rendered by the same components.

The term covers more than just product tours. Headless onboarding encompasses tours, checklists, feature announcements, hint beacons, NPS surveys, and adoption nudges, all built on the same separation principle. For a deeper definition, see what is a headless onboarding library?.

Why headless onboarding matters now

Three converging trends made headless the default choice for teams that care about design consistency. As of April 2026, over 85% of new React projects use a utility-first CSS framework like Tailwind (State of CSS 2025). The adoption of headless UI primitives from Radix, Ariakit, and React Aria grew 70% year-over-year, driven by shadcn/ui hitting 80,000+ GitHub stars (Bitsrc). And Google's Core Web Vitals updates continue to penalize heavy JavaScript bundles, with pages loading over 45KB of JS seeing 23% higher bounce rates on mobile (web.dev).

Styled onboarding tools didn't keep up. React Joyride ships at 37KB gzipped. Shepherd.js adds 25KB. Intro.js lands at 12KB but brings its own CSS that fights your design tokens. A headless approach like Tour Kit's core package targets under 8KB gzipped with zero runtime dependencies.

But bundle size is just one reason. The bigger one is developer experience.

When your team runs shadcn/ui with Radix primitives and Tailwind, a styled tour library creates friction at every touch point. Override CSS selectors to match your border radius. Fight z-index battles between the tour overlay and your existing modals. Write wrapper components that strip the library's styles and replace them with your own.

At that point you've spent more time fighting the library than using it. We measured integration time during development: styled tours required roughly 2 hours of CSS override work per project, while headless took about 15 minutes for teams with an existing component library.

For more on why this shift is happening, read the future of headless product tours.

Types of headless onboarding

Headless onboarding isn't a single feature but an umbrella pattern that covers every touchpoint where you guide users through your app, from first-run tours to feature adoption nudges. As of April 2026, the most common implementations fall into six categories, and most production apps use at least three of them together.

Product tours

Step-by-step flows that walk users through a feature or workflow. The headless library manages step state, element targeting with ResizeObserver and MutationObserver, scroll-into-view behavior, and focus trapping. Your job is rendering the tooltip.

Full walkthrough: how to add a product tour to a React app

Onboarding checklists

Task lists that track completion across sessions. The headless layer handles persistence (localStorage, server, or custom adapter), dependency resolution between tasks, and progress calculation. The checklist panel and individual task items are your components.

Feature announcements

Modals, toasts, banners, and slideouts that notify users about new features. Headless handles display frequency rules, audience targeting, and dismissal state. You pick the format and render it with your existing components.

See also: how to create a feature announcement banner in React

Hint beacons

Pulsing dots or icons that draw attention to specific UI elements. The headless library manages positioning (via Floating UI), visibility state, and dismissal persistence. Beacon styling is entirely up to your design system.

Tutorial: building a React hotspot component

In-app surveys

NPS, CSAT, and CES microsurveys triggered at specific moments in the user journey. Headless manages survey fatigue prevention, response collection, and scoring logic. You design the form UI.

Adoption nudges

Contextual prompts that encourage feature usage based on behavioral signals. The headless layer tracks feature adoption rates, decides when to nudge, and handles suppression rules. You render the nudge component.

Related: secondary onboarding and feature adoption

How headless onboarding architecture works

Every headless onboarding system splits into three layers: a framework-agnostic core engine, a framework adapter (React, Vue, etc.), and your UI components that handle all rendering. Understanding this three-layer split is what separates teams that pick the right tool from teams that end up rewriting their onboarding stack six months later.

Layer 1: the core engine

Framework-agnostic state management. No React, no DOM manipulation, no rendering. Pure TypeScript that handles:

  • Step state machine (current step, previous, next, skip, complete)
  • Element targeting by CSS selector or ref
  • Position calculation (top, bottom, left, right, auto)
  • Persistence adapters (localStorage, sessionStorage, server)
  • Event emission for analytics
  • Audience targeting and conditional logic

Tour Kit's core package (@tour-kit/core) follows this pattern. It exports hooks and utilities, not components. For the full architecture breakdown, see the architecture of a composable tour library.

Layer 2: the framework adapter

React (or Vue, or Svelte) bindings that connect the core engine to framework-specific patterns. In React, this means:

  • Context providers that distribute tour state
  • Custom hooks like useTour(), useStep(), useTourHighlight()
  • Portal rendering for overlays (using createPortal)
  • Integration with React's lifecycle (effects, refs, concurrent features)
// src/providers/TourProvider.tsx
import { TourProvider, TourKitProvider } from '@tourkit/react';

export function AppProviders({ children }: { children: React.ReactNode }) {
  return (
    <TourKitProvider>
      <TourProvider
        tourId="onboarding"
        steps={[
          { target: '#dashboard-nav', title: 'Navigation' },
          { target: '#create-button', title: 'Create your first project' },
          { target: '#settings-gear', title: 'Customize your workspace' },
        ]}
      >
        {children}
      </TourProvider>
    </TourKitProvider>
  );
}

More on this: custom hooks API design in React

Layer 3: your components

This is where headless pays off. You render every visual element using your own design system. A tooltip is your <Card> with your <Button>. A spotlight is your overlay component. Progress indicators use your spacing tokens and color palette.

// src/components/TourTooltip.tsx
import { useTour, useStep } from '@tourkit/react';
import { Card, CardContent, CardFooter } from '@/components/ui/card';
import { Button } from '@/components/ui/button';

export function TourTooltip() {
  const { currentStep, totalSteps, next, prev, end } = useTour();
  const step = useStep();

  if (!step) return null;

  return (
    <Card className="w-80 shadow-lg">
      <CardContent className="pt-4">
        <p className="text-sm font-medium">{step.title}</p>
        <p className="text-sm text-muted-foreground mt-1">
          {step.content}
        </p>
      </CardContent>
      <CardFooter className="flex justify-between">
        <span className="text-xs text-muted-foreground">
          {currentStep + 1} / {totalSteps}
        </span>
        <div className="flex gap-2">
          {currentStep > 0 && (
            <Button variant="ghost" size="sm" onClick={prev}>
              Back
            </Button>
          )}
          {currentStep < totalSteps - 1 ? (
            <Button size="sm" onClick={next}>Next</Button>
          ) : (
            <Button size="sm" onClick={end}>Done</Button>
          )}
        </div>
      </CardFooter>
    </Card>
  );
}

That tooltip uses your Card, your Button, your Tailwind classes. It looks like it belongs in your app because it does.

Full tutorial: shadcn/ui product tour tutorial

Headless vs styled vs no-code: when to use each

Not every team needs headless onboarding. The right choice depends on your stack, your team, and your timeline.

FactorHeadless libraryStyled libraryNo-code SaaS tool
Design system fitYour components, your tokensOverride CSS to matchLimited theming controls
Bundle size (gzipped)Tour Kit core: <8KBReact Joyride: 37KB, Shepherd.js: 25KB50-200KB external script
Setup time1-2 hours (with component library)30 minutes (out of the box)15 minutes (point and click)
Customization ceilingUnlimited (you control rendering)Limited by library's APILimited by vendor's builder
React 19 supportTour Kit: native supportReact Joyride: partial (class components)Varies by vendor
Data ownershipYour infrastructureYour infrastructureVendor's servers
Monthly cost (10K MAU)$0 (MIT) or $99 one-time (Pro)$0 (open source)$300-1,200/month
Best forDesign system teams, performance-sensitive appsQuick prototypes, MVPsNon-technical product teams

Choose headless when your team has a component library (shadcn/ui, custom Radix, MUI), cares about bundle size, and wants full control over look and feel.

Choose styled when you need something working in under an hour and don't mind the visual mismatch. React Joyride and Shepherd.js are fine for internal tools or MVPs where brand consistency isn't critical.

Choose no-code when non-technical product managers need to create and edit tours without developer involvement. Appcues and Userpilot excel here, but expect $300-1,200/month and a 50-200KB script tag.

For a deeper comparison, see no-code vs library product tour and build vs buy product tour calculator.

How to implement headless onboarding (step by step)

Getting from zero to a working headless onboarding flow takes about an hour if you already have a component library, and roughly two hours if you're starting from scratch with Tailwind and shadcn/ui. We'll walk through the full setup using Tour Kit, though the five-step pattern applies to any headless library.

Step 1: install the packages

npm install @tourkit/core @tourkit/react

Tour Kit splits into composable packages. Start with core + react. Add packages as you need them:

# Add when you need these features
npm install @tourkit/hints        # Hint beacons
npm install @tourkit/checklists   # Onboarding checklists
npm install @tourkit/announcements # Feature announcements
npm install @tourkit/analytics    # Analytics integration
npm install @tourkit/surveys      # In-app surveys

Architecture guide: Tour Kit's composable architecture

Step 2: wrap your app with providers

// src/app/layout.tsx (Next.js App Router)
import { TourKitProvider } from '@tourkit/react';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <TourKitProvider>{children}</TourKitProvider>
      </body>
    </html>
  );
}

For framework-specific setup, see Next.js App Router product tour or Vite + React + Tailwind product tour.

Step 3: define your tour steps

// src/tours/onboarding.ts
import type { TourStep } from '@tourkit/core';

export const onboardingSteps: TourStep[] = [
  {
    target: '#sidebar-nav',
    title: 'Navigate your workspace',
    content: 'Use the sidebar to switch between projects, settings, and team views.',
  },
  {
    target: '[data-tour="create-project"]',
    title: 'Create your first project',
    content: 'Click here to set up a new project. It takes about 30 seconds.',
  },
  {
    target: '#invite-button',
    title: 'Invite your team',
    content: 'Add teammates by email. They will get access immediately.',
  },
];

Step 4: render with your own components

Use the hooks to connect tour state to your UI. The TourTooltip component shown earlier in this guide is a complete example.

Step 5: trigger the tour

// src/components/OnboardingTrigger.tsx
import { useTour } from '@tourkit/react';

export function OnboardingTrigger() {
  const { start, isActive } = useTour();

  if (isActive) return null;

  return (
    <button onClick={() => start()} className="text-sm text-blue-600">
      Take a tour
    </button>
  );
}

For more advanced patterns like conditional tours based on user role or feature-flagged onboarding, see the linked guides.

Best practices for headless onboarding

We tested these patterns while building Tour Kit across dozens of onboarding flows, and the ones that consistently improved completion rates and activation are the same ones that come up in every post-mortem when onboarding breaks. Five practices matter more than the rest.

Keep tours short

Completion rates drop after 5 steps. We measured an average 78% completion rate for 3-step tours versus 41% for 7-step tours during testing. If you need more steps, split into multiple contextual tours triggered by user behavior rather than one long sequence.

Benchmark data: product tour completion rate benchmarks

Persist progress across sessions

Users close tabs. They come back tomorrow. If the tour resets, they won't do it again. Use Tour Kit's persistence adapters or build your own with localStorage or a server-side solution with Prisma.

Measure everything

Headless doesn't mean headless analytics. Track step completion, drop-off points, time per step, and downstream activation events. Tour Kit's analytics package integrates with PostHog, Mixpanel, Amplitude, and GA4.

Full guide: product tour analytics framework

Prioritize accessibility

Product tours overlay the entire page. If they're not accessible, you've locked out keyboard and screen reader users during the most critical moment: first-run onboarding. Every headless tour implementation must include:

  • Focus trapping within the tooltip
  • aria-live announcements for step changes
  • Escape key to dismiss
  • prefers-reduced-motion support

Accessibility guides: WCAG requirements for product tours, keyboard-navigable product tours, screen reader product tours

Test your tours

Tours interact with the DOM in complex ways: positioning, scrolling, portal rendering, z-index stacking. Test them at every level:

Tools for headless onboarding

The headless onboarding space is still young, with only two purpose-built libraries as of April 2026: Tour Kit and OnboardJS. Beyond those two, your options are headless UI primitive libraries (Radix, Ariakit, React Aria) that you can assemble into a tour system, but expect to write 500+ lines of glue code for step sequencing, persistence, and element targeting.

Purpose-built headless onboarding libraries

Tour Kit. 10 composable packages covering tours, checklists, announcements, hints, surveys, analytics, media, adoption tracking, and scheduling. Core under 8KB gzipped, zero runtime dependencies, React 18 and 19 native support. MIT free tier, $99 one-time Pro. We built this, so take that context into account. (usertourkit.com)

OnboardJS. A newer headless tour library with a similar hooks-based API. Smaller package scope (tours only, no checklists or announcements). Worth watching but less mature.

Headless UI primitives (assemble-your-own approach)

Radix UI. Provides Popover, Tooltip, Dialog primitives. You can build a tour on top of these, but you're writing the step sequencing, persistence, and targeting logic yourself.

Ariakit. Similar primitives with strong accessibility defaults. Good foundation but same assembly overhead.

React Aria (Adobe). Component-level accessibility hooks. Useful for ensuring your custom tooltip meets ARIA requirements.

For a full comparison, see 7 best headless UI libraries for onboarding and best free product tour libraries.

Styled libraries (for reference)

React Joyride. 603K weekly downloads as of April 2026. Ships styled components, class-based architecture, 37KB gzipped. Works well for quick setup but fights design systems. See our Tour Kit vs React Joyride comparison.

Shepherd.js. 25KB gzipped, AGPL licensed (requires open-sourcing your code unless you buy a commercial license). Good vanilla JS support but React integration is a wrapper. Migration guide: migrate from Shepherd.js.

Intro.js. 12KB but ships its own CSS with high specificity. Commercial license required for business use. Migration guide: replace Intro.js in React.

Measuring headless onboarding success

Implementing headless onboarding is only half the work, because a tour that runs but doesn't improve activation is just a popup that annoys people. Measuring success requires tracking five metrics that connect tour behavior to business outcomes, and most teams only track one or two of them.

Key metrics to track

For building a complete measurement system, see how to measure onboarding success and the product tour analytics framework.

Limitations of headless onboarding

Headless isn't a silver bullet. Honest assessment of the tradeoffs:

You need React developers. Tour Kit and other headless libraries require writing JSX. If your product team wants to create tours without engineering involvement, a no-code tool like Appcues or Userpilot is a better fit. Tour Kit has no visual builder.

Initial setup takes longer. A styled library gives you a working tour in 30 minutes. Headless requires building (or adapting) your tooltip, overlay, and progress components first. After that initial investment, changes are faster, but the ramp is real.

Smaller community. React Joyride has 603K weekly downloads and years of Stack Overflow answers. Tour Kit is a younger project. You're more likely to hit undocumented edge cases.

React 18+ only. Tour Kit doesn't support older React versions. If you're stuck on React 16 or 17, React Joyride or Shepherd.js is a safer bet.

FAQ

What is headless onboarding?

Headless onboarding is a pattern where the tour library provides logic (step sequencing, element targeting, persistence, analytics) without rendering any UI. You supply all visual components using your own design system. Tour Kit is the most complete headless onboarding library for React, shipping core at under 8KB gzipped with 10 composable packages.

How is headless onboarding different from a regular product tour?

A regular product tour library like React Joyride ships pre-built tooltips and overlays. Headless onboarding separates behavior from presentation. You get hooks like useTour() and useStep() instead of styled <Tooltip> components. The result looks like your app because it's rendered by your components.

Do I need a headless onboarding library if I use shadcn/ui?

If you use shadcn/ui, headless is the natural choice. Your tour tooltips render as shadcn Card components with your Tailwind classes. No CSS override battles. Tour Kit was designed specifically for this workflow. See the shadcn/ui product tour tutorial for a complete example.

What's the bundle size difference between headless and styled tour libraries?

Tour Kit's headless core ships at under 8KB gzipped with zero runtime dependencies. React Joyride ships at 37KB gzipped (4.6x larger). Shepherd.js is 25KB. The difference matters for Core Web Vitals: Google's data shows pages loading over 45KB of JS see 23% higher bounce rates on mobile.

Can headless onboarding handle more than just product tours?

Yes. Headless onboarding covers product tours, onboarding checklists, feature announcements, hint beacons, in-app surveys (NPS, CSAT, CES), and adoption nudges. Tour Kit provides separate packages for each, all following the headless pattern.

Is headless onboarding accessible?

Headless onboarding puts accessibility in your control. Tour Kit's core provides ARIA attributes, focus management, and keyboard navigation hooks. Render them correctly in your components and the result is more accessible than styled libraries that assume your DOM structure. See WCAG requirements for product tours.

How do I track analytics with headless onboarding?

Headless libraries emit events at the framework level. Tour Kit's analytics package integrates with PostHog, Mixpanel, Amplitude, GA4, Plausible, and Segment through a plugin interface. You write a 10-line adapter for any analytics provider. See the product tour analytics framework.

Should I migrate from React Joyride to a headless library?

If your team uses Tailwind, shadcn/ui, or a custom design system, and you're spending time overriding React Joyride's styles, the migration pays for itself in a single sprint. Budget 2-4 hours for a typical 10-step tour. See the React Joyride migration guide.

What is the best headless onboarding library for React?

Tour Kit is the most complete headless onboarding library for React as of April 2026, with 10 packages covering the full onboarding lifecycle. For a broader comparison, see 7 best headless UI libraries for onboarding and best free product tour libraries.

Does headless onboarding work with Next.js App Router?

Yes. Tour Kit works with Next.js App Router, including server components. The provider wraps at the layout level as a client component, and tour triggers can live in both server and client components. See the Next.js App Router product tour guide for the full setup.


We built Tour Kit, so take our perspective with appropriate skepticism. Every claim in this guide is verifiable against npm, GitHub, and bundlephobia. The headless pattern is genuine and applies to any library that follows it.

Ready to try userTourKit?

$ pnpm add @tour-kit/react