react-native-orbit-onboarding
v0.1.0
Published
A polished, flexible onboarding flow for React Native and Expo projects.
Maintainers
Readme
react-native-orbit-onboarding
A polished onboarding flow for React Native and Expo apps with strong defaults, zero Expo-only assumptions, and enough extension points to match a real product instead of a starter template.
Why this package exists
Most onboarding packages land in one of two bad places:
- too rigid to match an existing design system
- too bare to feel finished out of the box
react-native-orbit-onboarding is designed to sit in the middle:
- animated, production-ready layout out of the box
- works in Expo and bare React Native
- no navigation, Redux, gesture, icon, or theme framework coupling
- full control over copy, colors, illustrations, and footer rendering
- small dependency surface:
react,react-native,react-native-reanimated
Installation
Install the package and its peer dependencies.
npm install react-native-orbit-onboarding react-native-reanimatedyarn add react-native-orbit-onboarding react-native-reanimatedExpo setup
For Expo projects, install Reanimated using Expo's version-aware command:
npx expo install react-native-reanimated react-native-workletsAs of April 21, 2026, Expo's current Reanimated docs for SDK 54 say no extra Babel config is required because babel-preset-expo configures it automatically.
Reference:
Bare React Native setup
For React Native Community CLI apps, make sure Reanimated is configured correctly:
npm install react-native-reanimated react-native-workletsAdd the Worklets plugin last in babel.config.js:
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: ['react-native-worklets/plugin'],
};Then rebuild the native app:
cd ios && pod install && cd ..If you change Reanimated setup in an existing app, clear the Metro cache before testing again.
Reference:
Quick Start
import React from 'react';
import { Text, View } from 'react-native';
import Onboarding, { OnboardingPage } from 'react-native-orbit-onboarding';
const pages: OnboardingPage[] = [
{
title: 'Welcome to Orbit',
description: 'Guide new users with motion, structure, and a clear first-run story.',
emoji: '🪐',
backgroundColor: '#FFF7ED',
accentColor: '#EA580C',
},
{
title: 'Show Real Product Value',
description: 'Each slide can use emoji, local images, or your own custom illustration renderer.',
emoji: '⚡️',
backgroundColor: '#ECFEFF',
accentColor: '#0891B2',
},
{
title: 'Ship Faster',
description: 'Plug into your existing navigation or auth flow with a single onDone callback.',
emoji: '🚀',
backgroundColor: '#EEF2FF',
accentColor: '#4F46E5',
},
];
export function WelcomeScreen() {
return (
<Onboarding
pages={pages}
onDone={() => {
// navigate, persist completion, or open your app shell
}}
/>
);
}Custom Illustration Example
import React from 'react';
import { Text, View } from 'react-native';
import Onboarding, { OnboardingPage } from 'react-native-orbit-onboarding';
const pages: OnboardingPage[] = [
{
title: 'Built for your brand',
description: 'Swap emoji for any custom React Native illustration.',
backgroundColor: '#F0FDF4',
accentColor: '#15803D',
renderIllustration: ({ accentColor, isActive, width }) => (
<View
style={{
width: width * 0.56,
height: width * 0.56,
borderRadius: width * 0.28,
backgroundColor: accentColor,
alignItems: 'center',
justifyContent: 'center',
transform: [{ rotate: isActive ? '0deg' : '-8deg' }],
}}
>
<Text style={{ fontSize: 42 }}>🌿</Text>
</View>
),
},
];
export function BrandOnboarding() {
return <Onboarding pages={pages} onDone={() => {}} />;
}Custom Footer Example
Use renderFooter when you want total control over the action area.
<Onboarding
pages={pages}
onDone={finishOnboarding}
renderFooter={({ activeIndex, isLastPage, goToNext, complete, skip }) => (
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingHorizontal: 24,
paddingBottom: 24,
}}
>
<Text>{`${activeIndex + 1} / ${pages.length}`}</Text>
<View style={{ flexDirection: 'row', gap: 12 }}>
<Text onPress={skip}>Skip</Text>
<Text onPress={isLastPage ? complete : goToNext}>
{isLastPage ? 'Enter app' : 'Next'}
</Text>
</View>
</View>
)}
/>API
Onboarding
| Prop | Type | Default | Notes |
| --- | --- | --- | --- |
| pages | OnboardingPage[] | required | Slide content. |
| onDone | () => void | required | Called when the primary action is pressed on the last slide. |
| onSkip | () => void | undefined | If omitted, skip jumps to the last page. |
| onIndexChange | (index: number) => void | undefined | Fires when the active slide changes. |
| initialIndex | number | 0 | Initial slide position. |
| showPagination | boolean | true | Hides the default pagination dots when false. |
| showSkip | boolean | true | Hides the default skip action. |
| nextLabel | string | "Continue" | Default primary button text before the last slide. |
| doneLabel | string | "Get Started" | Default primary button text on the last slide. |
| skipLabel | string | "Skip" | Default skip text. |
| theme | OnboardingTheme | built-in theme | Global palette overrides. |
| style | StyleProp<ViewStyle> | undefined | Root container style. |
| slideStyle | StyleProp<ViewStyle> | undefined | Applied to each slide wrapper. |
| footerStyle | StyleProp<ViewStyle> | undefined | Applied to the default footer wrapper. |
| illustrationContainerStyle | StyleProp<ViewStyle> | undefined | Applied to the slide illustration shell. |
| titleStyle | StyleProp<TextStyle> | undefined | Applied to all titles. |
| descriptionStyle | StyleProp<TextStyle> | undefined | Applied to all descriptions. |
| buttonStyle | StyleProp<ViewStyle> | undefined | Applied to the default primary button. |
| buttonTextStyle | StyleProp<TextStyle> | undefined | Applied to the default primary button text. |
| skipTextStyle | StyleProp<TextStyle> | undefined | Applied to the default skip text. |
| renderFooter | (props) => ReactNode | undefined | Replaces the full default footer. |
| testID | string | undefined | Applied to the root container. |
OnboardingPage
| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| title | string | yes | Main headline. |
| description | string | no | Supporting copy. |
| emoji | string | no | Quickest zero-asset illustration option. |
| image | ImageSourcePropType | no | Local or remote image source. |
| renderIllustration | (props) => ReactNode | no | Full custom illustration renderer. |
| backgroundColor | string | no | Per-slide background. |
| accentColor | string | no | Per-slide accent for dots, labels, and shadows. |
| titleColor | string | no | Per-slide title color override. |
| descriptionColor | string | no | Per-slide body color override. |
| accessibilityLabel | string | no | Accessibility text for the illustration. |
| key | string | no | Stable React key if you need one. |
OnboardingTheme
| Field | Type | Default |
| --- | --- | --- |
| backgroundColor | string | #F5F1E8 |
| accentColor | string | #1D4ED8 |
| textColor | string | #0F172A |
| secondaryTextColor | string | #475569 |
| surfaceColor | string | #FFFFFF |
| buttonBackgroundColor | string | #0F172A |
| buttonTextColor | string | #FFFFFF |
| inactiveDotColor | string | #CBD5E1 |
| skipTextColor | string | #64748B |
Exports
import Onboarding, {
DEFAULT_THEME,
Onboarding,
OnboardingPage,
OnboardingProps,
OnboardingTheme,
} from 'react-native-orbit-onboarding';Build And Publish
npm run build
npm packThis package ships:
- CommonJS output in
lib/commonjs - ESM output in
lib/module - TypeScript declarations in
lib/typescript - raw source entry for Metro via the
react-nativeexport
Before publishing to npm, check that the package name is available and update package.json if you want to publish under a scope.
Design Notes
- The package does not own navigation state. Keep route transitions in your app.
- The package does not depend on Expo modules, icon libraries, gesture handlers, or safe-area packages.
- Reanimated powers motion, but the surface area stays simple enough to theme or replace.
License
MIT
