react-native-tour-kit
v1.0.3
Published
Guided product tours for React Native with spotlight overlays, tooltips, and route-aware step flows.
Maintainers
Readme
react-native-tour-kit
Guided product tours for React Native with spotlight overlays, route-aware steps, scroll/list reveal helpers, and optional seen-state persistence.
Features
- Spotlight overlays with
rectangle,rounded-rectangle,circle, orovalcutouts TourProvider+TourTargetAPI- Programmatic tour control with
useTour() - Route-aware steps via navigation adapter support
- Built-in helpers for
ScrollView,FlatList, andSectionList - Optional prompt before tour starts
- Pluggable storage for tracking seen/completed tours
- Custom tooltip renderer support
Installation
npm install react-native-tour-kit
npx expo install react-native-svgPeer requirements:
react >= 18react-native >= 0.72react-native-svg >= 13
Quick Start
import React from "react";
import { Button, Text, View } from "react-native";
import {
TourProvider,
TourTarget,
defineTours,
useTour,
} from "react-native-tour-kit";
const tours = defineTours({
homeOnboarding: [
{
id: "welcome",
target: "welcome-card",
title: "Welcome",
description: "This card gives you a quick overview.",
placement: "bottom",
},
{
id: "cta",
target: "primary-cta",
title: "Take action",
description: "Tap here to continue.",
placement: "top",
},
],
});
function HomeScreen() {
const { startTour } = useTour();
return (
<View style={{ flex: 1, padding: 16, gap: 16 }}>
<TourTarget id="welcome-card">
<View
style={{ padding: 16, borderRadius: 12, backgroundColor: "#eef2ff" }}
>
<Text>Welcome to the app</Text>
</View>
</TourTarget>
<TourTarget id="primary-cta">
<Button
title="Continue"
onPress={() => {}}
/>
</TourTarget>
<Button
title="Start Tour"
onPress={() => startTour("homeOnboarding")}
/>
</View>
);
}
export default function App() {
return (
<TourProvider tours={tours}>
<HomeScreen />
</TourProvider>
);
}Important Layout Note (Spotlight + Margins)
If a spotlighted element has margins, those margins are included in the measured target area and can make the spotlight appear taller/larger than expected.
Use margins on a parent wrapper instead, and keep the actual TourTarget child margin-free for accurate spotlight sizing.
API Overview
Core exports
TourProviderTourTargetuseTourdefineToursTourScrollViewTourFlatListTourSectionListcreateExpoRouterAdapter
Tour step shape
Each step includes:
target(required): target id registered byTourTargettitle(required)description?placement?:top | bottom | left | right | autoallowInteractionWithTarget?route?andnavigationMode?for route-aware stepsreadiness?(delayMs,isReady,waitFor,timeoutMs,pollIntervalMs)scrollToTarget?,scrollContainerId?,scrollTargetIndex?,scrollSectionIndex?
useTour() controller methods
startTour(stepsOrTourId, options?)stopTour()nextStep()previousStep()goToStep(idOrIndex)hasTour(id)/getTour(id)isTourSeen(id)/markTourSeen(id)/clearTourSeen(id)getState()
Scroll/List Helpers
Use the wrapped containers when a step may be off-screen.
TourScrollViewwithid="..."TourFlatListwithid="..."TourSectionListwithid="..."
Then set in your step:
scrollToTarget: truescrollContainerId: "same-id-as-wrapper"
For virtualized lists, optionally provide:
scrollTargetIndex/scrollSectionIndexgetTourTargetIdprop onTourFlatList/TourSectionList
Route-aware Tours (Expo Router)
Create a navigation adapter and pass it to TourProvider:
import { usePathname, useLocalSearchParams, useRouter } from "expo-router";
import { TourProvider, createExpoRouterAdapter } from "react-native-tour-kit";
function TourRoot({ children }: { children: React.ReactNode }) {
const router = useRouter();
const pathname = usePathname();
const params = useLocalSearchParams();
const pathnameRef = useRef(pathname);
const paramsRef = useRef(params);
useEffect(() => {
pathnameRef.current = pathname;
paramsRef.current = params;
}, [pathname, params]);
const navigation = useMemo(
() =>
createExpoRouterAdapter({
push: (href) => router.push(href),
replace: (href) => router.replace(href),
back: () => router.back(),
getPathname: () => pathnameRef.current,
getParams: () => paramsRef.current,
}),
[router],
);
return <TourProvider navigation={navigation}>{children}</TourProvider>;
}Customization
TourProvider supports customization props including:
renderTooltipspotlightShape,spotlightBorderRadius,spotlightPaddingoverlayOpacity,overlayColor,closeOnOverlayPressbuttonColors,tooltipBackground,tooltipTextColorpromptconfig for start prompt text/visibility- lifecycle callbacks via individual props or
lifecycle
Persistence (Seen Tours)
Pass a storage adapter to TourProvider:
const storage = {
keyPrefix: "my-app-tour",
getItem: (key: string) => AsyncStorage.getItem(key),
setItem: (key: string, value: string) => AsyncStorage.setItem(key, value),
removeItem: (key: string) => AsyncStorage.removeItem(key),
};Then use:
isTourSeen("tourId")markTourSeen("tourId")clearTourSeen("tourId")
License
MIT
