Beautiful, performant Coach Mark library for React Native with smooth animations, customizable tooltips, and TypeScript support. Create engaging product tours and onboarding experiences.
- π¨ Multiple shapes - Circle, rounded rectangle, and pill shapes
- π± Smart positioning - Auto-placement with boundary detection
- π Auto-scroll - Automatically scroll to off-screen elements
- βΏοΈ Accessible - Screen reader support and reduced motion
- πΎ Show once - Built-in persistence (never annoy users twice)
- π Themeable - Light/dark modes and custom styling
- π§ Custom tooltips - Full control with render props
- π― Lifecycle hooks - onEnter, onExit, onBeforeEnter, onBeforeScroll
- β‘οΈ Performant - No screenshots, pure vector masking
- π¦ TypeScript - Full type safety included
- π Cross-platform - iOS, Android, and Web
npm install @edwardloopez/react-native-coachmark react-native-svg react-native-reanimatedThis library depends on:
- react-native-svg (β₯13.0.0) - For vector graphics
- react-native-reanimated (β₯3.0.0) - For smooth animations
Note: Follow the Reanimated installation guide to configure the Babel plugin.
For "show once" functionality, install one of these:
# AsyncStorage (most common)
npm install @react-native-async-storage/async-storage
# OR MMKV (faster, recommended)
npm install react-native-mmkvWrap your app with the provider and add the overlay:
import { CoachmarkProvider, CoachmarkOverlay } from '@edwardloopez/react-native-coachmark';
export default function App() {
return (
<CoachmarkProvider>
<YourApp />
<CoachmarkOverlay />
</CoachmarkProvider>
);
}Wrap elements you want to highlight:
import { CoachmarkAnchor } from '@edwardloopez/react-native-coachmark';
<CoachmarkAnchor id="create-button" shape="circle">
<Button title="Create" onPress={handleCreate} />
</CoachmarkAnchor>
<CoachmarkAnchor id="filters" shape="rect">
<View style={styles.filters}>
<Text>Filters</Text>
</View>
</CoachmarkAnchor>import { useCoachmark, createTour } from '@edwardloopez/react-native-coachmark';
function HomeScreen() {
const { start } = useCoachmark();
const startTour = () => {
start(
createTour('onboarding', [
{
id: 'create-button',
title: 'Create New Item',
description: 'Tap here to add a new item',
placement: 'bottom',
},
{
id: 'filters',
title: 'Filter Results',
description: 'Use these to narrow your search',
placement: 'top',
},
], {
showOnce: true, // Show only once per user
delay: 500, // Wait 500ms before starting
})
);
};
return <Button title="Start Tour" onPress={startTour} />;
}Root provider that manages tour state.
<CoachmarkProvider theme={customTheme} storage={storageAdapter}>
{children}
</CoachmarkProvider>Renders the spotlight and tooltip. Add once at app root.
Marks elements for highlighting.
<CoachmarkAnchor
id="button-id" // Required: Unique identifier
shape="circle" // 'circle' | 'rect' | 'pill'
padding={12} // Space around element (pixels)
radius={8} // Corner radius for rect/pill
scrollRef={scrollViewRef} // For auto-scroll feature
>
{children}
</CoachmarkAnchor>Props:
| Prop | Type | Description |
|---|---|---|
id |
string (required) | Unique identifier for this anchor |
shape |
'circle' | 'rect' | 'pill' |
Spotlight shape (overrides step config) |
padding |
number | Extra space around element (pixels) |
radius |
number | Corner radius for rounded shapes (pixels) |
scrollRef |
React.Ref | Ref to parent ScrollView/FlatList (required for autoFocus) |
Control tours programmatically.
const { start, next, back, skip, stop, state } = useCoachmark();
// Start a tour
start(tour);
// Navigate
next(); // Next step
back(); // Previous step
skip(); // End tour
// Check state
state.isActive // Is tour running?
state.index // Current step (0-based)Create a tour configuration.
const tour = createTour(
'my-tour', // Unique identifier
[
{
id: 'anchor-id', // Anchor to highlight
title: 'Title', // Tooltip title
description: 'Info', // Tooltip description
placement: 'bottom', // Tooltip position
shape: 'circle', // Spotlight shape
},
],
{
showOnce: true, // Show only once
delay: 500, // Start delay (ms)
}
);Step Options:
| Option | Type | Default | Description |
|---|---|---|---|
id |
string | required | Anchor ID to highlight |
title |
string | - | Tooltip title text |
description |
string | - | Tooltip description text |
placement |
'top' | 'bottom' | 'left' | 'right' | 'auto' |
'auto' |
Tooltip position |
shape |
'circle' | 'rect' | 'pill' |
- | Spotlight shape |
padding |
number | - | Space around highlight (pixels) |
radius |
number | - | Corner radius for rect/pill shapes (pixels) |
autoFocus |
'always' | 'ifNeeded' |
- | Auto-scroll behavior |
scrollBehavior |
'smooth' | 'instant' |
- | Scroll animation |
scrollPadding |
number | 20 | Space from screen edges when scrolling (pixels) |
scrollDelay |
number | 150 | Delay after scroll before showing tooltip (ms) |
onBeforeEnter |
async function | - | Callback before step starts (return false to skip) |
onBeforeScroll |
async function | - | Callback before auto-scrolling starts |
onEnter |
function | - | Callback when step becomes active |
onExit |
function | - | Callback when leaving step |
renderTooltip |
React.ComponentType | - | Custom tooltip component for this step |
Tour Options:
| Option | Type | Default | Description |
|---|---|---|---|
showOnce |
boolean | false | Show tour only once (requires storage) |
delay |
number | 0 | Delay before tour starts (milliseconds) |
renderTooltip |
React.ComponentType | - | Global custom tooltip renderer for all steps |
Scan with Expo Go to try on your device:
OR
View on Expo!
Explore advanced features and best practices:
- π§ Advanced Usage - Auto-scroll, lifecycle hooks, custom themes, plugins
- π‘ Examples - Real-world use cases and complete code samples
- βΏοΈ Accessibility - Make tours inclusive for all users
- β Best Practices - Design, performance, and testing guidelines
- π NPM Package
- π Report Issues
- π¬ Discussions
Using this library? Open a PR to add your app here!
Contributions welcome! See CONTRIBUTING.md for guidelines.
Made with β€οΈ for the React Native community
