React Native walkthrough
A walkthrough takes a user through your interface one screen element at a time: dim everything, spotlight one control, explain it, advance. This page shows how to build one in React Native with @wrack/react-native-tour-guide — including the parts that are usually fiddly, like keeping the tooltip on screen and scrolling to steps below the fold.
What is a React Native walkthrough library?
A walkthrough library renders an overlay above your app, measures the component you want to explain, cuts a hole in the overlay around it, and positions a tooltip next to it. You describe the walkthrough as an array of steps — each step points at a component ref and carries a title and description — and the library handles measurement, positioning, animation, and navigation between steps.
How do I install it?
npm install @wrack/react-native-tour-guide react-native-svg
# yarn add @wrack/react-native-tour-guide react-native-svg
# pnpm add @wrack/react-native-tour-guide react-native-svg
# Expo: npx expo install @wrack/react-native-tour-guide react-native-svg
react-native-svg is the only required peer dependency. There are no native modules to link.
How do I build a walkthrough?
Wrap your app once, then define steps and call startTour.
import { TourGuideProvider, TourGuideOverlay } from '@wrack/react-native-tour-guide';
export default function App() {
return (
<TourGuideProvider>
<RootNavigator />
<TourGuideOverlay />
</TourGuideProvider>
);
}
import { useRef } from 'react';
import { View, Text, Pressable, StyleSheet } from 'react-native';
import { useTourGuide } from '@wrack/react-native-tour-guide';
function DashboardScreen() {
const { startTour } = useTourGuide();
const searchRef = useRef(null);
const filterRef = useRef(null);
const avatarRef = useRef(null);
const runWalkthrough = () =>
startTour(
[
{
id: 'search',
targetRef: searchRef,
title: 'Search anything',
description: 'Find any project, file, or teammate from here.',
targetStyle: styles.search,
},
{
id: 'filter',
targetRef: filterRef,
title: 'Narrow it down',
description: 'Filter results by status, owner, or date.',
targetStyle: styles.filter,
},
{
id: 'avatar',
targetRef: avatarRef,
title: 'Your account',
description: 'Settings and preferences live here.',
targetStyle: styles.avatar,
},
],
{
showProgressDots: true,
skipButtonText: 'Skip walkthrough',
doneButtonText: 'Got it',
onTourEnd: (completed) => console.log('walkthrough finished:', completed),
}
);
return (
<View>
<View ref={searchRef} style={styles.search} />
<View ref={filterRef} style={styles.filter} />
<View ref={avatarRef} style={styles.avatar} />
<Pressable onPress={runWalkthrough}>
<Text>Take the walkthrough</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
search: { height: 44, borderRadius: 22, backgroundColor: '#EEE' },
filter: { height: 36, borderRadius: 8, backgroundColor: '#EEE' },
avatar: { width: 48, height: 48, borderRadius: 24, backgroundColor: '#CCC' },
});
Passing each component’s own style as targetStyle is what makes the spotlight match its shape: the pill-shaped search bar gets a pill spotlight, the avatar gets a circle, the filter chip keeps its 8px corners.
How do I walk through a long, scrollable screen?
Most real walkthroughs cross the fold. Give the tour a scrollRef plus a way to read the current scroll position, and off-screen steps are scrolled into view — far enough that the tooltip fits too, not just the target.
const scrollRef = useRef(null);
const [scrollY, setScrollY] = useState(0);
startTour(steps, {
scrollRef,
getCurrentScrollOffset: () => scrollY,
});
<ScrollView
ref={scrollRef}
onScroll={(e) => setScrollY(e.nativeEvent.contentOffset.y)}
scrollEventThrottle={16}
>
{/* walkthrough targets */}
</ScrollView>
The same config works for FlatList and SectionList. For one specific step that needs different behaviour, set scrollToTarget on that step with its own offset, animated, and getCurrentScrollOffset.
How do I control the walkthrough programmatically?
useTourGuide() returns the full controller, so you can drive it from anywhere inside the provider:
const {
startTour, nextStep, prevStep, goToStep,
skipTour, endTour, pauseTour, resumeTour,
isActive, isPaused, currentStep,
} = useTourGuide();
pauseTour() hides the overlay but keeps the walkthrough’s position — useful when a modal or a permissions dialog interrupts. resumeTour() picks up on the same step.
How do I skip steps that don’t apply?
Set active: false on any step and it is removed from the walkthrough, with the step counter renumbering itself:
startTour([
{ id: 'welcome', targetRef: welcomeRef, title: 'Welcome', description: '…' },
{ id: 'upgrade', targetRef: upgradeRef, title: 'Upgrade', description: '…', active: !isPremium },
{ id: 'done', targetRef: doneRef, title: 'All set', description: '…' },
]);
How do I style the walkthrough?
Use one of the four built-in themes, or build your own with createTheme():
import { createTheme, vibrantTheme } from '@wrack/react-native-tour-guide';
startTour(steps, { ...vibrantTheme });
const brand = createTheme({
tooltipStyles: { primaryButtonColor: '#FF6B35', backgroundColor: '#1B1B3A' },
spotlightStyles: { overlayOpacity: 0.7, enablePulse: true, pulseColor: '#FF6B35' },
});
startTour(steps, { ...brand });
For total control, pass renderTooltip and render your own component — it receives title, description, currentStep, totalSteps, and onNext / onPrev / onSkip.
FAQ
What’s the difference between a walkthrough, a tour, and coach marks?
They overlap heavily. A walkthrough or tour is a sequence of steps shown in order, usually on first launch. Coach marks are typically one or two contextual hints shown at the moment a feature becomes relevant. The same step-based API covers all three — see coach marks and app tours.
Can a walkthrough step have no highlighted element?
Yes. Omit targetRef and the step renders as a centered tooltip with no spotlight — handy for an intro or outro card.
How long should a walkthrough be?
Three to seven steps. Longer sequences see steep drop-off, and every step should always be skippable.
Does it work with React Navigation?
Yes, as long as TourGuideProvider wraps the navigator and TourGuideOverlay is rendered inside it. A single walkthrough measures targets on the currently mounted screen; for cross-screen flows, start a separate tour per screen and use tourId to tell them apart.
Does it need a custom dev build?
No. The only required peer dependency is react-native-svg, so it runs in Expo Go. See Expo onboarding tours.