Advanced onboarding flow for React Native apps with personalization questions, gradient backgrounds, animations, and customizable slides. Built with SOLID, DRY, KISS principles.
- π¨ Beautiful gradient backgrounds with smooth transitions
- β Personalization questions - Get to know your users
- π Multiple question types - Single choice, multiple choice, text input, slider, rating
- β Built-in validation - Required fields, min/max values, custom validators
- π Conditional slides - Skip slides based on previous answers
- πΎ Persistent storage - Save user answers and onboarding state
- π― Type-safe - Full TypeScript support
- π Customizable - Custom header, footer, and slide components
- π± Universal - Works on iOS, Android, and Web
- π Production-ready - Used in hundreds of apps
npm install @umituz/react-native-onboardingnpm install \
@umituz/react-native-storage \
@umituz/react-native-localization \
@umituz/react-native-design-system-theme \
@umituz/react-native-design-system \
@umituz/react-native-design-system-atoms \
@react-native-community/slider \
expo-linear-gradient \
react-native-safe-area-context \
zustandimport { OnboardingScreen } from '@umituz/react-native-onboarding';
const slides = [
{
id: '1',
title: 'Welcome to Our App',
description: 'Discover amazing features',
icon: 'π',
gradient: ['#667eea', '#764ba2'],
},
{
id: '2',
title: 'Stay Organized',
description: 'Keep track of everything',
icon: 'π',
gradient: ['#f093fb', '#f5576c'],
},
];
<OnboardingScreen
slides={slides}
onComplete={() => console.log('Onboarding completed')}
/>import { OnboardingScreen, OnboardingSlide } from '@umituz/react-native-onboarding';
const slides: OnboardingSlide[] = [
// Welcome slide
{
id: '1',
type: 'welcome',
title: 'Welcome to FishWise',
description: 'Your personal aquarium assistant',
icon: 'π ',
gradient: ['#667eea', '#764ba2'],
},
// Question: Experience level
{
id: '2',
type: 'question',
title: 'What\'s your experience level?',
description: 'Help us personalize your experience',
icon: 'π―',
gradient: ['#f093fb', '#f5576c'],
question: {
id: 'experience_level',
type: 'single_choice',
question: 'Select your experience level',
storageKey: '@user_experience_level',
validation: { required: true },
options: [
{ id: 'beginner', label: 'Beginner', icon: 'π±' },
{ id: 'intermediate', label: 'Intermediate', icon: 'πΏ' },
{ id: 'expert', label: 'Expert', icon: 'π³' },
],
},
},
// Question: Tank size
{
id: '3',
type: 'question',
title: 'What\'s your tank size?',
description: 'This helps us recommend suitable fish',
icon: 'π',
gradient: ['#4facfe', '#00f2fe'],
question: {
id: 'tank_size',
type: 'slider',
question: 'Select your tank size (gallons)',
storageKey: '@user_tank_size',
validation: { required: true, min: 10, max: 500 },
defaultValue: 50,
},
},
// Question: Interests
{
id: '4',
type: 'question',
title: 'What interests you most?',
description: 'Select all that apply',
icon: 'β€οΈ',
gradient: ['#fa709a', '#fee140'],
question: {
id: 'interests',
type: 'multiple_choice',
question: 'Choose your interests',
storageKey: '@user_interests',
validation: { required: true, minSelections: 1, maxSelections: 3 },
options: [
{ id: 'freshwater', label: 'Freshwater Fish', icon: 'π' },
{ id: 'saltwater', label: 'Saltwater Fish', icon: 'π ' },
{ id: 'plants', label: 'Aquatic Plants', icon: 'πΏ' },
{ id: 'equipment', label: 'Equipment & Tech', icon: 'βοΈ' },
],
},
},
// Completion slide
{
id: '5',
type: 'completion',
title: 'You\'re All Set!',
description: 'Let\'s start your aquarium journey',
icon: 'π',
gradient: ['#30cfd0', '#330867'],
},
];
import Slider from '@react-native-community/slider';
<OnboardingScreen
slides={slides}
SliderComponent={Slider}
onComplete={async () => {
const userData = onboardingStore.getUserData();
console.log('User answers:', userData.answers);
// Save to backend, navigate to home, etc.
}}
/>| Prop | Type | Default | Description |
|---|---|---|---|
slides |
OnboardingSlide[] |
Required | Array of slides to display |
onComplete |
() => void | Promise<void> |
- | Callback when onboarding is completed |
onSkip |
() => void | Promise<void> |
- | Callback when onboarding is skipped |
skipButtonText |
string |
"Skip" | Custom skip button text |
nextButtonText |
string |
"Next" | Custom next button text |
getStartedButtonText |
string |
"Get Started" | Custom get started button text |
showSkipButton |
boolean |
true |
Show skip button |
showBackButton |
boolean |
true |
Show back button |
showProgressBar |
boolean |
true |
Show progress bar |
showDots |
boolean |
true |
Show dots indicator |
showProgressText |
boolean |
true |
Show progress text (1 of 5) |
storageKey |
string |
- | Custom storage key for completion state |
autoComplete |
boolean |
false |
Auto-complete on last slide |
SliderComponent |
React.ComponentType |
- | Required if using slider questions. Import from @react-native-community/slider |
interface OnboardingSlide {
id: string;
type?: 'info' | 'question' | 'welcome' | 'completion';
title: string;
description: string;
icon: string; // Emoji or Lucide icon name
gradient: string[]; // [startColor, endColor] or [color1, color2, color3]
image?: string;
features?: string[];
question?: OnboardingQuestion;
skipIf?: (answers: Record<string, any>) => boolean;
}{
type: 'single_choice',
question: 'What is your goal?',
options: [
{ id: 'weight_loss', label: 'Weight Loss', icon: 'π' },
{ id: 'muscle_gain', label: 'Muscle Gain', icon: 'πͺ' },
],
}{
type: 'multiple_choice',
question: 'Select your interests',
validation: { minSelections: 1, maxSelections: 3 },
options: [
{ id: 'yoga', label: 'Yoga', icon: 'π§' },
{ id: 'running', label: 'Running', icon: 'π' },
{ id: 'swimming', label: 'Swimming', icon: 'π' },
],
}{
type: 'text_input',
question: 'What is your name?',
placeholder: 'Enter your name',
validation: { required: true, minLength: 2, maxLength: 50 },
}SliderComponent prop to OnboardingScreen:
import Slider from '@react-native-community/slider';
<OnboardingScreen
slides={slides}
SliderComponent={Slider}
onComplete={handleComplete}
/>{
type: 'slider',
question: 'What is your age?',
validation: { min: 18, max: 100 },
defaultValue: 25,
}Note: Make sure @react-native-community/slider is installed and properly linked (run pod install for iOS).
{
type: 'rating',
question: 'Rate your experience',
validation: { max: 5 },
}<OnboardingScreen
slides={slides}
renderHeader={({ isFirstSlide, onBack, onSkip }) => (
<View>
{!isFirstSlide && <Button onPress={onBack}>Back</Button>}
<Button onPress={onSkip}>Skip</Button>
</View>
)}
/><OnboardingScreen
slides={slides}
renderFooter={({ currentIndex, totalSlides, isLastSlide, onNext }) => (
<View>
<Text>{currentIndex + 1} / {totalSlides}</Text>
<Button onPress={onNext}>
{isLastSlide ? 'Get Started' : 'Next'}
</Button>
</View>
)}
/>{
id: '3',
title: 'Advanced Features',
description: 'Only for experienced users',
icon: 'β‘',
gradient: ['#667eea', '#764ba2'],
skipIf: (answers) => answers.experience_level === 'beginner',
}import { useOnboarding } from '@umituz/react-native-onboarding';
const { userData, getAnswer } = useOnboarding();
// Get specific answer
const experienceLevel = getAnswer('experience_level');
// Get all answers
const allAnswers = userData.answers;
// Check if onboarding was completed
const isComplete = userData.completedAt !== undefined;
// Check if onboarding was skipped
const wasSkipped = userData.skipped === true;import { useOnboarding } from '@umituz/react-native-onboarding';
const { reset } = useOnboarding();
// Reset onboarding (useful for testing or settings)
await reset();- β iOS
- β Android
- β Web
Built with Domain-Driven Design (DDD):
- Domain Layer: Entities and interfaces (business logic)
- Infrastructure Layer: Storage and hooks (state management)
- Presentation Layer: Components and screens (UI)
MIT
Contributions are welcome! Please open an issue or PR.
For issues and questions, please open an issue on GitHub.