
Is there a product tour library that works with Vue and React?
If you run Vue on one product and React on another (or both in the same codebase), the standard advice is "pick Shepherd.js." That advice isn't wrong, but it skips the part where Shepherd's React and Vue wrappers are thin convenience layers over a vanilla JS core. You get cross-framework coverage, but you lose the idiomatic hooks and composability that made you choose Vue or React in the first place.
The real question isn't "does a cross-framework tour library exist?" It does. Several do. The question is whether the developer experience survives the abstraction.
npm install @tourkit/core @tourkit/reactWe tested the major options in a Vite 6 + React 19 and a Nuxt 3 + Vue 3 project. Here's what we found.
Short answer
As of April 2026, three product tour libraries work across both Vue and React: Shepherd.js (13.7K GitHub stars, 656 kB unpacked), Driver.js (25.5K stars, 83 kB unpacked), and Intro.js (23.8K stars, 874 kB unpacked, AGPL-licensed). All three are vanilla JavaScript cores with framework wrappers. None provides first-class Vue 3 Composition API hooks or first-class React hooks from a shared engine. For React-only teams, Tour Kit ships at under 8 kB gzipped with native hooks and WCAG 2.1 AA accessibility. A @tour-kit/vue package is on the roadmap.
How cross-framework tour libraries actually work
Every library claiming "works with Vue and React" follows the same pattern: a vanilla JavaScript engine that manipulates the DOM directly, wrapped in thin framework adapters. The core calculates positions, draws overlays, manages step state. A Vue component wraps it for Vue projects. A React component wraps it for React projects.
This matters because wrapper quality varies wildly. Shepherd.js has official wrappers for React, Vue, Angular, even Ember. But the React wrapper is a class-based component that hasn't been rewritten for hooks. The Vue wrapper targets Vue 2 and Vue 3 but doesn't use the Composition API internally. You end up calling imperative methods on a ref instead of using reactive state.
Driver.js skips the wrapper question entirely. Pure vanilla JS. You call driver.highlight() and driver.drive() from inside a useEffect or onMounted. Honest, at least. You know what you're getting.
"Most teams severely underestimate the work involved: handling async DOM updates, keyboard navigation, accessibility, responsive behavior on mobile, animations, and tour state management," notes Chameleon's Vue product tours guide. The wrapper approach pushes all of that complexity onto you.
Detailed comparison
| Feature | Shepherd.js | Driver.js | Intro.js | Tour Kit |
|---|---|---|---|---|
| React support | Official wrapper | Vanilla JS (manual) | Community wrapper | Native hooks |
| Vue support | Official wrapper | Vanilla JS (manual) | Community wrapper | Roadmap |
| Bundle size (unpacked) | 656 kB | 83 kB | 874 kB | Core: ~20 kB, React: ~30 kB |
| Bundle size (gzipped) | ~25 kB | ~5 kB | ~30 kB | Core: <8 kB, React: <12 kB |
| TypeScript | Yes | Yes (built in TS) | Types available | Yes (strict mode) |
| License | MIT | MIT | AGPL-3.0 / Commercial | MIT (core) / Commercial (extended) |
| WCAG 2.1 AA | Partial (built-in keyboard nav) | No explicit compliance | No explicit compliance | Yes (focus trap, ARIA, reduced motion) |
| React 19 compatible | Wrapper untested | Yes (no React dependency) | Wrapper untested | Yes |
| Analytics built-in | No | No | No | Yes (@tourkit/analytics) |
| Checklists | No | No | No | Yes (@tourkit/checklists) |
| Last npm publish | ~17 days ago | ~4 months ago | ~9 months ago | Pre-release |
| GitHub stars | 13,716 | 25,538 | 23,850 | New |
| Best for | Multi-framework teams needing one library | Lightweight spotlights and guided tours | Quick prototyping (check AGPL first) | React teams wanting headless composability |
Data sourced from npm, GitHub, and bundlephobia as of April 2026.
What about Vue-only options?
Vue Tour (pulsardev) was the go-to Vue tour library for years. It hit 2,443 GitHub stars and ~20K weekly npm downloads. But its last publish was over five years ago. It doesn't support Vue 3's Composition API natively, and there's no TypeScript support.
VueJS Tour by GlobalHive targets Vue 3 with Composition API support, but adoption is limited. v-onboarding is lightweight and Composition API-ready, though it lacks accessibility features or analytics.
The Vue tour ecosystem has a maintenance problem. "As soon as you feel the tipping point — multiple tours, multiple teams, governance questions — it's worth considering a product-led platform instead of a library," Chameleon notes. That's fair advice if you're scaling. But for teams that want to own their onboarding code, the pickings are thin.
The wrapper tradeoff you should understand
Here's the pattern with framework-agnostic libraries. You install Shepherd.js in a React project:
// src/components/TourButton.tsx
import { useEffect, useRef } from 'react';
import Shepherd from 'shepherd.js';
export function TourButton() {
const tourRef = useRef<Shepherd.Tour | null>(null);
useEffect(() => {
const tour = new Shepherd.Tour({
defaultStepOptions: {
cancelIcon: { enabled: true },
classes: 'shepherd-theme-arrows',
},
});
tour.addStep({
id: 'welcome',
text: 'Welcome to the dashboard.',
attachTo: { element: '#dashboard-header', on: 'bottom' },
buttons: [{ text: 'Next', action: tour.next }],
});
tourRef.current = tour;
return () => tour.cancel();
}, []);
return <button onClick={() => tourRef.current?.start()}>Start tour</button>;
}You're managing tour state imperatively through refs. No reactive step tracking. No access to current step index through React state. No composition with other hooks. You're writing the glue code that a native library would give you for free.
Compare that with a React-native approach:
// src/components/ProductTour.tsx
import { TourProvider, useTour } from '@tourkit/react';
const steps = [
{ id: 'welcome', target: '#dashboard-header', content: 'Welcome to the dashboard.' },
{ id: 'sidebar', target: '#sidebar-nav', content: 'Navigate between sections here.' },
];
function TourControls() {
const { currentStep, totalSteps, next, back, isActive } = useTour();
if (!isActive) return null;
return (
<div role="dialog" aria-label={`Tour step ${currentStep + 1} of ${totalSteps}`}>
<p>{steps[currentStep].content}</p>
<button onClick={back} disabled={currentStep === 0}>Back</button>
<button onClick={next}>{currentStep === totalSteps - 1 ? 'Finish' : 'Next'}</button>
</div>
);
}
export function ProductTour() {
return (
<TourProvider steps={steps}>
<TourControls />
</TourProvider>
);
}Reactive state. Composable. Accessible by default. But React-only. That's the tradeoff.
Decision framework: which library fits your stack?
If your entire frontend is Vue 3: Use v-onboarding for simple tours or VueJS Tour for Composition API support. Accept that neither has accessibility compliance or analytics. Budget time for manual keyboard navigation and ARIA attributes.
If your entire frontend is React 18+: Use Tour Kit for headless composability with built-in accessibility, or React Joyride (~400K weekly downloads) if you want opinionated styling out of the box. Tour Kit gives you more control; Joyride gives you faster setup. Both support React 19.
If you need one library across Vue and React: Use Shepherd.js. It has the widest framework support, active maintenance (last publish ~17 days ago as of April 2026), and built-in keyboard navigation. Accept the 656 kB unpacked size and imperative wrapper DX. For lighter needs, Driver.js at 83 kB covers tours and spotlights without the weight.
If you're migrating from Vue to React (or vice versa): Start with a framework-agnostic library (Shepherd.js or Driver.js) during the migration. Once you've settled on a single framework, evaluate framework-native options for better DX.
If accessibility is a hard requirement:
Tour Kit is the only library making explicit WCAG 2.1 AA compliance claims with focus trapping, ARIA landmarks, keyboard navigation, and prefers-reduced-motion support. Shepherd.js has partial keyboard navigation built in. Everything else requires manual implementation.
"A React team should not force a framework-agnostic library if the wrapper quality is poor, and a vanilla JS team should not drag in React-only assumptions," Userorbit's comparison points out. Match the library to the stack, not the other way around.
What about web components?
CSS anchor positioning is worth watching. CSS-Tricks documented a <hand-hold> web component that uses native CSS anchor-name and position-area properties to position tour tooltips without any JavaScript position calculations. It works in Chromium 125+ today.
This matters for cross-framework scenarios because web components work everywhere. A <tour-step> custom element would render in React, Vue, Angular, Svelte, or plain HTML without wrappers. The positioning would be CSS-native. The framework runtime wouldn't matter.
We're not there yet. Browser support is Chromium-only, polyfills add weight, and you still need JavaScript for step sequencing, analytics, and keyboard navigation. But in 12-18 months, a web component + CSS anchor positioning approach could make the "which framework" question irrelevant for tour positioning.
What we recommend (and why)
We built Tour Kit, so take this with appropriate skepticism. Every claim below is verifiable against npm, GitHub, and bundlephobia.
For React teams, Tour Kit's headless architecture means you render your own components, compose with your own hooks, and keep full control over styling. The core ships at under 8 kB gzipped with zero runtime dependencies. You get WCAG 2.1 AA accessibility without configuration. And the extended packages (analytics, checklists, surveys, announcements, scheduling) exist in the same monorepo, so they share types and context.
Tour Kit doesn't support Vue today. The core package (@tour-kit/core) is framework-agnostic by design — step state, position calculation, storage, keyboard navigation all live outside React. A @tour-kit/vue package using Vue 3 Composition API is on the roadmap. When it ships, it would share the same core logic with identical TypeScript types and accessibility guarantees. No wrapper tradeoffs.
Honest limitations: no visual builder (you write code), React 18+ only, smaller community than Shepherd.js or React Joyride. The Vue package doesn't exist yet. If you need cross-framework support today, Shepherd.js or Driver.js are your practical options.
Get started with Tour Kit: usertourkit.com
FAQ
Can Shepherd.js work with both Vue 3 and React 19?
Shepherd.js has official wrappers for Vue and React. The Vue wrapper supports Vue 3, and the vanilla JS core works with React 19 since it doesn't touch React internals. The React wrapper is still class-based, though. As of April 2026, Shepherd.js has 13,716 GitHub stars with a publish ~17 days ago.
What is the lightest product tour library that works with Vue and React?
Driver.js is the lightest cross-framework option at 83 kB unpacked (roughly 5 kB gzipped). It's pure vanilla JavaScript with no framework wrappers, which means you call it imperatively from Vue's onMounted or React's useEffect. Tour Kit's core is under 8 kB gzipped but currently supports only React. Shepherd.js is 656 kB unpacked and Intro.js is 874 kB unpacked.
Is Intro.js free for commercial use?
Not for closed-source apps. Intro.js uses AGPL-3.0, which requires you to open-source your entire application if you distribute it. Commercial use requires a paid license, a common gotcha that surfaces during legal reviews. Driver.js, Shepherd.js, React Joyride, and Tour Kit's core all use MIT, which permits unrestricted commercial use.
Does any product tour library support WCAG 2.1 AA accessibility across frameworks?
None make explicit WCAG 2.1 AA compliance claims as of April 2026. Shepherd.js includes built-in keyboard navigation, which is a start. Tour Kit provides focus trapping, ARIA landmarks, keyboard navigation, and prefers-reduced-motion support, though only in React today. Accessibility remains the widest gap in cross-framework tour libraries.
Should I use a framework-agnostic library or a framework-native one?
Use a framework-native library if you're committed to one framework. You get reactive state, composable hooks, better TypeScript integration. Pick a framework-agnostic option (Shepherd.js, Driver.js) only if you genuinely run multiple frameworks in production. The wrapper DX tradeoff is real: you lose reactive state management for cross-framework coverage.
Disclosure: We built Tour Kit. Data points in this article are sourced from npm, GitHub, and bundlephobia and can be independently verified. Tour Kit is MIT-licensed (core packages) with commercial extended packages.
Related articles

What are the best Appcues alternatives for developers?
Compare 7 Appcues alternatives built for developers. See bundle sizes, React 19 support, pricing, and code examples to pick the right onboarding tool.
Read article
What is the best open-source onboarding framework? (2026)
Compare open-source onboarding frameworks by bundle size, React 19 support, accessibility, and full-stack coverage. Honest recommendations with data.
Read article
What is the best product tour library for SSR (server-side rendering)?
Compare product tour libraries for SSR frameworks like Next.js, Remix, and Nuxt. See which handle server rendering, hydration, and React Server Components.
Read article
What is the best shadcn/ui compatible tour library?
Compare 7 tour libraries for shadcn/ui compatibility. See bundle sizes, headless support, and Tailwind integration to pick the right fit.
Read article