# Onboarding

> A customizable multi-step onboarding flow with smooth animations and gesture support.

**BNA UI** — a React Native / Expo component library.
These components render through `react-native`, not the DOM: there are no HTML
elements, no Tailwind classes and no Radix primitives. Source is copied into your
project and imported through `@/components/ui/*`, `@/components/charts/*`,
`@/hooks/*` and `@/theme/*`. Colours come from the `useColor` hook rather than
hardcoded hex; sizing tokens (`HEIGHT`, `FONT_SIZE`, `BORDER_RADIUS`, `CORNERS`)
come from `@/theme/globals`.

- Docs: https://ui.ahmedbna.com/docs/components/onboarding
- Markdown: https://ui.ahmedbna.com/docs/components/onboarding.md
- Structured JSON (props, usage, source, examples): https://ui.ahmedbna.com/r/ai/onboarding.json
- Install payload (source plus every file it imports): https://ui.ahmedbna.com/r/onboarding.json
- Install: `npx bna-ui add onboarding`
- npm dependencies: `expo-haptics`, `lucide-react-native`, `react-native-gesture-handler`, `react-native-reanimated`, `react-native-svg`, `react-native-worklets`
- Registry dependencies: `mode-provider`, `useColorScheme`, `colors`, `useColor`, `useHaptics`, `globals`, `text`, `view`, `icon`, `spinner`, `button`
- Preview recording: https://demo.ahmedbna.com/0198-onboarding-demo.MP4

---

**Example:** A basic onboarding flow with multiple steps

```tsx
// components/demo/onboarding/onboarding-demo.tsx
import { Onboarding, useOnboarding } from '@/components/ui/onboarding';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';

export const OnboardingPresets = {
  welcome: [
    {
      id: 'welcome',
      title: 'Welcome to Our App',
      description:
        'Discover amazing features and get started with your journey.',
      icon: <Text style={{ fontSize: 80 }}>👋</Text>,
    },
    {
      id: 'features',
      title: 'Powerful Features',
      description:
        'Experience cutting-edge functionality designed to make your life easier.',
      icon: <Text style={{ fontSize: 80 }}>⚡</Text>,
    },
    {
      id: 'personalize',
      title: 'Personalize Your Experience',
      description: 'Customize the app to match your preferences and workflow.',
      icon: <Text style={{ fontSize: 80 }}>🎨</Text>,
    },
    {
      id: 'ready',
      title: "You're All Set!",
      description:
        "Everything is ready. Let's start exploring what you can achieve.",
      icon: <Text style={{ fontSize: 80 }}>🚀</Text>,
    },
  ],

  features: [
    {
      id: 'organize',
      title: 'Stay Organized',
      description: 'Keep all your important information in one secure place.',
      icon: <Text style={{ fontSize: 80 }}>📋</Text>,
    },
    {
      id: 'collaborate',
      title: 'Collaborate Seamlessly',
      description: 'Work together with your team in real-time, anywhere.',
      icon: <Text style={{ fontSize: 80 }}>🤝</Text>,
    },
    {
      id: 'automate',
      title: 'Automate Your Workflow',
      description: 'Set up smart automations to save time and reduce errors.',
      icon: <Text style={{ fontSize: 80 }}>🤖</Text>,
    },
  ],

  security: [
    {
      id: 'secure',
      title: 'Your Data is Secure',
      description:
        'We use end-to-end encryption to keep your information safe.',
      icon: <Text style={{ fontSize: 80 }}>🔒</Text>,
    },
    {
      id: 'privacy',
      title: 'Privacy First',
      description: 'We never share your personal data with third parties.',
      icon: <Text style={{ fontSize: 80 }}>🛡️</Text>,
    },
    {
      id: 'control',
      title: "You're in Control",
      description: 'Manage your privacy settings and data preferences anytime.',
      icon: <Text style={{ fontSize: 80 }}>⚙️</Text>,
    },
  ],
};

export function OnboardingDemo() {
  const { hasCompletedOnboarding, completeOnboarding, skipOnboarding } =
    useOnboarding();

  if (hasCompletedOnboarding) {
    return (
      <View
        style={{
          flex: 1,
          justifyContent: 'center',
          alignItems: 'center',
          paddingHorizontal: 24,
        }}
      >
        <Text variant='title'>Welcome Back!</Text>
        <Text variant='body'>You've already completed the onboarding.</Text>
      </View>
    );
  }

  return (
    <Onboarding
      steps={OnboardingPresets.welcome}
      onComplete={completeOnboarding}
      onSkip={skipOnboarding}
      showSkip={true}
      showProgress={true}
      swipeEnabled={true}
      primaryButtonText='Get Started'
      skipButtonText='Skip'
      nextButtonText='Next'
      backButtonText='Back'
    />
  );
}
```

## Installation

### CLI

```bash
npx bna-ui add onboarding
```

### Manual

**1.** Install the following dependencies:

```bash
npx expo install react-native-gesture-handler react-native-reanimated
```

**2.** Copy and paste the following code into your project.

```tsx
// components/ui/onboarding.tsx
import { Button } from '@/components/ui/button';
import { Text } from '@/components/ui/text';
import { useColor } from '@/hooks/useColor';
import React, { useEffect, useRef, useState } from 'react';
import {
  AccessibilityInfo,
  ScrollView,
  StyleSheet,
  useWindowDimensions,
  View,
  ViewStyle,
} from 'react-native';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
  runOnJS,
  useAnimatedStyle,
  useSharedValue,
  withSpring,
} from 'react-native-reanimated';

export interface OnboardingStep {
  id: string;
  title: string;
  description: string;
  image?: React.ReactNode;
  icon?: React.ReactNode;
  backgroundColor?: string;
}

export interface OnboardingProps {
  steps: OnboardingStep[];
  onComplete: () => void;
  onSkip?: () => void;
  showSkip?: boolean;
  showProgress?: boolean;
  swipeEnabled?: boolean;
  primaryButtonText?: string;
  skipButtonText?: string;
  nextButtonText?: string;
  backButtonText?: string;
  style?: ViewStyle;
  children?: React.ReactNode;
}

// Enhanced Onboarding Step Component for complex layouts
interface OnboardingStepContentProps {
  step: OnboardingStep;
  isActive: boolean;
  children?: React.ReactNode;
}

export function Onboarding({
  steps,
  onComplete,
  onSkip,
  showSkip = true,
  showProgress = true,
  swipeEnabled = true,
  primaryButtonText = 'Get Started',
  skipButtonText = 'Skip',
  nextButtonText = 'Next',
  backButtonText = 'Back',
  style,
  children,
}: OnboardingProps) {
  const { width: screenWidth } = useWindowDimensions();
  const [currentStep, setCurrentStep] = useState(0);
  const scrollViewRef = useRef<ScrollView>(null);
  const translateX = useSharedValue(0);

  const backgroundColor = useColor('background');
  const primaryColor = useColor('primary');
  const mutedColor = useColor('mutedForeground');

  const isLastStep = currentStep === steps.length - 1;
  const isFirstStep = currentStep === 0;

  useEffect(() => {
    const step = steps[currentStep];
    if (!step) return;
    AccessibilityInfo.announceForAccessibility(
      `${step.title}. Step ${currentStep + 1} of ${steps.length}.`
    );
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [currentStep]);

  const handleNext = () => {
    if (isLastStep) {
      onComplete();
    } else {
      const nextStep = currentStep + 1;
      setCurrentStep(nextStep);
      scrollViewRef.current?.scrollTo({
        x: nextStep * screenWidth,
        animated: true,
      });
    }
  };

  const handleBack = () => {
    if (!isFirstStep) {
      const prevStep = currentStep - 1;
      setCurrentStep(prevStep);
      scrollViewRef.current?.scrollTo({
        x: prevStep * screenWidth,
        animated: true,
      });
    }
  };

  const handleSkip = () => {
    if (onSkip) {
      onSkip();
    } else {
      onComplete();
    }
  };

  // Modern gesture handling with Gesture API
  const panGesture = Gesture.Pan()
    .enabled(swipeEnabled)
    .onUpdate((event) => {
      translateX.value = event.translationX;
    })
    .onEnd((event) => {
      const { translationX, velocityX } = event;
      const shouldSwipe =
        Math.abs(translationX) > screenWidth * 0.3 || Math.abs(velocityX) > 500;

      if (shouldSwipe) {
        if (translationX > 0 && !isFirstStep) {
          // Swipe right - go back
          runOnJS(handleBack)();
        } else if (translationX < 0 && !isLastStep) {
          // Swipe left - go next
          runOnJS(handleNext)();
        }
      }

      translateX.value = withSpring(0);
    });

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: translateX.value }],
  }));

  const renderProgressDots = () => {
    if (!showProgress) return null;

    return (
      <View
        style={styles.progressContainer}
        accessibilityElementsHidden
        importantForAccessibility='no-hide-descendants'
      >
        {steps.map((_, index) => (
          <View
            key={index}
            style={[
              styles.progressDot,
              {
                backgroundColor:
                  index === currentStep ? primaryColor : mutedColor,
                opacity: index === currentStep ? 1 : 0.3,
              },
            ]}
          />
        ))}
      </View>
    );
  };

  const renderStep = (step: OnboardingStep, index: number) => {
    const isActive = index === currentStep;

    return (
      <Animated.View
        key={step.id}
        style={[
          styles.stepContainer,
          { width: screenWidth },
          { backgroundColor: step.backgroundColor || backgroundColor },
          { opacity: isActive ? 1 : 0.8 },
        ]}
      >
        <View style={styles.contentContainer}>
          {step.image && (
            <View style={styles.imageContainer}>{step.image}</View>
          )}

          {step.icon && !step.image && (
            <View style={styles.imageContainer}>{step.icon}</View>
          )}

          <View style={styles.textContainer}>
            <Text variant='title' style={styles.title}>
              {step.title}
            </Text>
            <Text variant='body' style={styles.description}>
              {step.description}
            </Text>
          </View>

          {children && <View style={styles.customContent}>{children}</View>}
        </View>
      </Animated.View>
    );
  };

  return (
    <View style={[styles.container, { backgroundColor }, style]}>
      <GestureDetector gesture={panGesture}>
        <Animated.View style={[styles.container, animatedStyle]}>
          <ScrollView
            ref={scrollViewRef}
            horizontal
            pagingEnabled
            showsHorizontalScrollIndicator={false}
            scrollEnabled={swipeEnabled}
            onMomentumScrollEnd={(event) => {
              const newStep = Math.round(
                event.nativeEvent.contentOffset.x / screenWidth
              );
              setCurrentStep(newStep);
            }}
          >
            {steps.map((step, index) => renderStep(step, index))}
          </ScrollView>
        </Animated.View>
      </GestureDetector>

      {/* Progress Dots */}
      {renderProgressDots()}

      {/* Skip Button */}
      {showSkip && !isLastStep && (
        <View style={styles.skipContainer}>
          <Button variant='ghost' onPress={handleSkip}>
            {skipButtonText}
          </Button>
        </View>
      )}

      {/* Navigation Buttons */}
      <View style={styles.buttonContainer}>
        {!isFirstStep && (
          <Button variant='outline' onPress={handleBack} style={{ flex: 1 }}>
            {backButtonText}
          </Button>
        )}

        <Button
          variant='default'
          onPress={handleNext}
          style={[...(isFirstStep ? [styles.fullWidthButton] : [{ flex: 2 }])]}
        >
          {isLastStep ? primaryButtonText : nextButtonText}
        </Button>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  stepContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    paddingHorizontal: 24,
  },
  contentContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    maxWidth: 400,
  },
  imageContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    marginBottom: 40,
    minHeight: 200,
  },
  textContainer: {
    alignItems: 'center',
    paddingHorizontal: 20,
    marginBottom: 40,
  },
  title: {
    textAlign: 'center',
    marginBottom: 16,
    paddingHorizontal: 20,
  },
  description: {
    textAlign: 'center',
    lineHeight: 24,
    paddingHorizontal: 20,
  },
  customContent: {
    alignItems: 'center',
    paddingHorizontal: 20,
    marginTop: 20,
  },
  progressContainer: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    paddingVertical: 20,
  },
  progressDot: {
    width: 8,
    height: 8,
    borderRadius: 4,
    marginHorizontal: 4,
  },
  skipContainer: {
    position: 'absolute',
    top: 60,
    right: 10,
    zIndex: 1,
  },
  buttonContainer: {
    width: '100%',
    height: 90,
    flexDirection: 'row',
    paddingHorizontal: 24,
    paddingBottom: 40,
    gap: 12,
  },
  fullWidthButton: {
    flex: 1,
  },
});

// Onboarding Hook for managing state
export function useOnboarding() {
  const [hasCompletedOnboarding, setHasCompletedOnboarding] = useState(false);
  const [currentOnboardingStep, setCurrentOnboardingStep] = useState(0);

  const completeOnboarding = async () => {
    try {
      // In a real app, you'd save this to AsyncStorage or similar
      setHasCompletedOnboarding(true);
      console.log('Onboarding completed and saved');
    } catch (error) {
      console.error('Failed to save onboarding completion:', error);
    }
  };

  const resetOnboarding = () => {
    setHasCompletedOnboarding(false);
    setCurrentOnboardingStep(0);
  };

  const skipOnboarding = async () => {
    await completeOnboarding();
  };

  return {
    hasCompletedOnboarding,
    currentOnboardingStep,
    setCurrentOnboardingStep,
    completeOnboarding,
    resetOnboarding,
    skipOnboarding,
  };
}
```

**3.** Update the import paths to match your project setup.

**4.** Make sure to configure react-native-gesture-handler and
react-native-reanimated in your project following their installation guides.

## Usage

```tsx
import { Onboarding, OnboardingStep } from '@/components/ui/onboarding';
```

```tsx
const steps: OnboardingStep[] = [
  {
    id: '1',
    title: 'Welcome',
    description: 'Get started with our amazing app',
    icon: <WelcomeIcon />,
  },
  {
    id: '2',
    title: 'Explore Features',
    description: 'Discover all the powerful features we offer',
    icon: <FeaturesIcon />,
  },
  {
    id: '3',
    title: 'Get Started',
    description: "You are all set! Let's begin your journey",
    icon: <StartIcon />,
  },
];

<Onboarding
  steps={steps}
  onComplete={() => console.log('Onboarding completed')}
  onSkip={() => console.log('Onboarding skipped')}
/>;
```

## Examples

#### Default

**Example:** A basic onboarding flow with multiple steps

```tsx
// components/demo/onboarding/onboarding-demo.tsx
import { Onboarding, useOnboarding } from '@/components/ui/onboarding';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';

export const OnboardingPresets = {
  welcome: [
    {
      id: 'welcome',
      title: 'Welcome to Our App',
      description:
        'Discover amazing features and get started with your journey.',
      icon: <Text style={{ fontSize: 80 }}>👋</Text>,
    },
    {
      id: 'features',
      title: 'Powerful Features',
      description:
        'Experience cutting-edge functionality designed to make your life easier.',
      icon: <Text style={{ fontSize: 80 }}>⚡</Text>,
    },
    {
      id: 'personalize',
      title: 'Personalize Your Experience',
      description: 'Customize the app to match your preferences and workflow.',
      icon: <Text style={{ fontSize: 80 }}>🎨</Text>,
    },
    {
      id: 'ready',
      title: "You're All Set!",
      description:
        "Everything is ready. Let's start exploring what you can achieve.",
      icon: <Text style={{ fontSize: 80 }}>🚀</Text>,
    },
  ],

  features: [
    {
      id: 'organize',
      title: 'Stay Organized',
      description: 'Keep all your important information in one secure place.',
      icon: <Text style={{ fontSize: 80 }}>📋</Text>,
    },
    {
      id: 'collaborate',
      title: 'Collaborate Seamlessly',
      description: 'Work together with your team in real-time, anywhere.',
      icon: <Text style={{ fontSize: 80 }}>🤝</Text>,
    },
    {
      id: 'automate',
      title: 'Automate Your Workflow',
      description: 'Set up smart automations to save time and reduce errors.',
      icon: <Text style={{ fontSize: 80 }}>🤖</Text>,
    },
  ],

  security: [
    {
      id: 'secure',
      title: 'Your Data is Secure',
      description:
        'We use end-to-end encryption to keep your information safe.',
      icon: <Text style={{ fontSize: 80 }}>🔒</Text>,
    },
    {
      id: 'privacy',
      title: 'Privacy First',
      description: 'We never share your personal data with third parties.',
      icon: <Text style={{ fontSize: 80 }}>🛡️</Text>,
    },
    {
      id: 'control',
      title: "You're in Control",
      description: 'Manage your privacy settings and data preferences anytime.',
      icon: <Text style={{ fontSize: 80 }}>⚙️</Text>,
    },
  ],
};

export function OnboardingDemo() {
  const { hasCompletedOnboarding, completeOnboarding, skipOnboarding } =
    useOnboarding();

  if (hasCompletedOnboarding) {
    return (
      <View
        style={{
          flex: 1,
          justifyContent: 'center',
          alignItems: 'center',
          paddingHorizontal: 24,
        }}
      >
        <Text variant='title'>Welcome Back!</Text>
        <Text variant='body'>You've already completed the onboarding.</Text>
      </View>
    );
  }

  return (
    <Onboarding
      steps={OnboardingPresets.welcome}
      onComplete={completeOnboarding}
      onSkip={skipOnboarding}
      showSkip={true}
      showProgress={true}
      swipeEnabled={true}
      primaryButtonText='Get Started'
      skipButtonText='Skip'
      nextButtonText='Next'
      backButtonText='Back'
    />
  );
}
```

#### With Images

**Example:** Onboarding flow with custom images for each step

```tsx
// components/demo/onboarding/onboarding-images.tsx
import { Image } from '@/components/ui/image';
import { Onboarding, OnboardingStep } from '@/components/ui/onboarding';
import React from 'react';

const WelcomeImage = () => (
  <Image
    source={{
      uri: 'https://images.unsplash.com/photo-1637858868799-7f26a0640eb6?q=80&w=2960&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
    }}
    width={300}
    aspectRatio={1}
    variant='circle'
  />
);

const FeaturesImage = () => (
  <Image
    source={{
      uri: 'https://images.unsplash.com/photo-1644190022446-04b99df7259a?q=80&w=2012&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
    }}
    width={300}
    aspectRatio={1}
  />
);

const StartImage = () => (
  <Image
    source={{
      uri: 'https://images.unsplash.com/photo-1575737698350-52e966f924d4?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
    }}
    width={420}
    aspectRatio={9 / 14}
  />
);

export function OnboardingImages() {
  const steps: OnboardingStep[] = [
    {
      id: '1',
      title: 'Welcome to the Team',
      description:
        'Join thousands of users who have already discovered the power of our platform.',
      image: <WelcomeImage />,
    },
    {
      id: '2',
      title: 'Powerful Features',
      description:
        'Access advanced tools and features that will help you achieve your goals faster.',
      image: <FeaturesImage />,
    },
    {
      id: '3',
      title: 'Ready to Launch',
      description:
        "Everything is set up and ready. Let's start building something amazing together!",
      image: <StartImage />,
    },
  ];

  return (
    <Onboarding
      steps={steps}
      onComplete={() => console.log('Onboarding with images completed!')}
      onSkip={() => console.log('Onboarding with images skipped!')}
      primaryButtonText="Let's Go"
      nextButtonText='Continue'
    />
  );
}
```

#### Custom Styling

**Example:** Onboarding with custom colors and styling

```tsx
// components/demo/onboarding/onboarding-styled.tsx
import { Onboarding, OnboardingStep } from '@/components/ui/onboarding';
import { Feather } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import React from 'react';

const GradientIcon = ({
  iconName,
  colors,
}: {
  iconName: string;
  colors: [string, string];
}) => (
  <LinearGradient
    colors={colors}
    style={{
      padding: 24,
      borderRadius: 70,
      alignItems: 'center',
      justifyContent: 'center',
      shadowColor: '#000',
      shadowOffset: { width: 0, height: 4 },
      shadowOpacity: 0.15,
      shadowRadius: 12,
      elevation: 6,
    }}
  >
    <Feather name={iconName as any} size={64} color='white' />
  </LinearGradient>
);

export function OnboardingStyled() {
  const steps: OnboardingStep[] = [
    {
      id: '1',
      title: 'Secure & Private',
      description:
        'Your data is protected with end-to-end encryption. We prioritize your privacy above all else.',
      icon: <GradientIcon iconName='shield' colors={['#667eea', '#764ba2']} />,
      backgroundColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
    },
    {
      id: '2',
      title: 'Lightning Fast',
      description:
        'Experience blazing fast performance with our optimized infrastructure and smart caching.',
      icon: <GradientIcon iconName='zap' colors={['#f093fb', '#f5576c']} />,
      backgroundColor: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
    },
    {
      id: '3',
      title: 'Always Connected',
      description:
        'Stay connected with real-time sync across all your devices. Never miss an important update.',
      icon: <GradientIcon iconName='wifi' colors={['#4facfe', '#00f2fe']} />,
      backgroundColor: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
    },
  ];

  return (
    <Onboarding
      steps={steps}
      onComplete={() => console.log('Styled onboarding completed!')}
      onSkip={() => console.log('Styled onboarding skipped!')}
      primaryButtonText='Start Now'
      nextButtonText='Next Step'
      skipButtonText='Skip Intro'
      style={{ backgroundColor: '#1a1a2e' }}
    />
  );
}
```

#### No Skip Button

**Example:** Onboarding flow without skip functionality

```tsx
// components/demo/onboarding/onboarding-no-skip.tsx
import { Onboarding, OnboardingStep } from '@/components/ui/onboarding';
import { Feather } from '@expo/vector-icons';
import React from 'react';
import { View } from 'react-native';

const InfoIcon = ({ name, color }: { name: string; color: string }) => (
  <View
    style={{
      padding: 20,
      backgroundColor: `${color}20`,
      borderRadius: 60,
      borderWidth: 2,
      borderColor: color,
    }}
  >
    <Feather name={name as any} size={60} color={color} />
  </View>
);

export function OnboardingNoSkip() {
  const steps: OnboardingStep[] = [
    {
      id: '1',
      title: 'Setup Your Profile',
      description:
        "Let's start by setting up your profile. This helps us personalize your experience.",
      icon: <InfoIcon name='user' color='#8b5cf6' />,
    },
    {
      id: '2',
      title: 'Choose Preferences',
      description:
        'Select your preferences to customize the app according to your needs and workflow.',
      icon: <InfoIcon name='settings' color='#06b6d4' />,
    },
    {
      id: '3',
      title: 'Enable Notifications',
      description:
        'Stay updated with important notifications. You can always change these settings later.',
      icon: <InfoIcon name='bell' color='#f59e0b' />,
    },
    {
      id: '4',
      title: 'All Set!',
      description:
        "Congratulations! Your account is now ready. Let's dive in and explore the features.",
      icon: <InfoIcon name='check-circle' color='#10b981' />,
    },
  ];

  return (
    <Onboarding
      steps={steps}
      onComplete={() => console.log('Required onboarding completed!')}
      showSkip={false}
      primaryButtonText='Complete Setup'
      nextButtonText='Continue'
      backButtonText='Previous'
    />
  );
}
```

#### Swipe Disabled

**Example:** Onboarding with swipe gestures disabled

```tsx
// components/demo/onboarding/onboarding-no-swipe.tsx
import { Onboarding, OnboardingStep } from '@/components/ui/onboarding';
import { Feather } from '@expo/vector-icons';
import React from 'react';
import { View } from 'react-native';

const StepIcon = ({
  name,
  bgColor,
  iconColor,
}: {
  name: string;
  bgColor: string;
  iconColor: string;
}) => (
  <View
    style={{
      padding: 18,
      backgroundColor: bgColor,
      borderRadius: 50,
      shadowColor: '#000',
      shadowOffset: { width: 0, height: 2 },
      shadowOpacity: 0.1,
      shadowRadius: 8,
      elevation: 3,
    }}
  >
    <Feather name={name as any} size={56} color={iconColor} />
  </View>
);

export function OnboardingNoSwipe() {
  const steps: OnboardingStep[] = [
    {
      id: '1',
      title: 'Tutorial Mode',
      description:
        'Follow along with our step-by-step tutorial. Use the buttons below to navigate at your own pace.',
      icon: <StepIcon name='book-open' bgColor='#ede9fe' iconColor='#7c3aed' />,
    },
    {
      id: '2',
      title: 'Learn the Basics',
      description:
        'Master the fundamental features that will help you get the most out of our platform.',
      icon: <StepIcon name='layers' bgColor='#dcfce7' iconColor='#16a34a' />,
    },
    {
      id: '3',
      title: 'Practice Makes Perfect',
      description:
        'Try out the features yourself in a safe environment before working with real data.',
      icon: <StepIcon name='target' bgColor='#fef3c7' iconColor='#d97706' />,
    },
  ];

  return (
    <Onboarding
      steps={steps}
      onComplete={() => console.log('Tutorial completed!')}
      onSkip={() => console.log('Tutorial skipped!')}
      swipeEnabled={false}
      showProgress={true}
      primaryButtonText='Start Using App'
      nextButtonText='Next Lesson'
      skipButtonText='Skip Tutorial'
    />
  );
}
```

#### Custom Buttons

**Example:** Onboarding with custom button text

```tsx
// components/demo/onboarding/onboarding-custom-buttons.tsx
import { Onboarding, OnboardingStep } from '@/components/ui/onboarding';
import { Heart, Rocket, Target } from 'lucide-react-native';
import React from 'react';

export function OnboardingCustomButtons() {
  const steps: OnboardingStep[] = [
    {
      id: '1',
      title: '🎉 Welcome Aboard!',
      description:
        "We're thrilled to have you join our community of innovators and creators.",
      icon: <Heart color='#ee5a52' size={100} />,
    },
    {
      id: '2',
      title: '🚀 Boost Your Productivity',
      description:
        'Discover powerful tools that will transform the way you work and collaborate.',
      icon: <Rocket color='#4ecdc4' size={100} />,
    },
    {
      id: '3',
      title: '🎯 Achieve Your Goals',
      description:
        'Set ambitious targets and track your progress with our advanced analytics.',
      icon: <Target color='#45b7d1' size={100} />,
    },
  ];

  return (
    <Onboarding
      steps={steps}
      onComplete={() => console.log('Custom buttons onboarding completed!')}
      onSkip={() => console.log('Custom buttons onboarding skipped!')}
      primaryButtonText='🚀 Launch App'
      nextButtonText='👉 Continue'
      backButtonText='👈 Back'
      skipButtonText='⏭️ Skip for Now'
    />
  );
}
```

#### With Hook

**Example:** Using the onboarding hook for state management

```tsx
// components/demo/onboarding/onboarding-hook.tsx
import { Button } from '@/components/ui/button';
import {
  Onboarding,
  OnboardingStep,
  useOnboarding,
} from '@/components/ui/onboarding';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React from 'react';

function MainApp() {
  const { resetOnboarding } = useOnboarding();

  return (
    <View
      style={{
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        padding: 20,
        backgroundColor: '#f8fafc',
      }}
    >
      <View style={{ alignItems: 'center', marginBottom: 40 }}>
        {/* <Text>{}</Text> */}
        <Text variant='heading' style={{ marginTop: 20, textAlign: 'center' }}>
          Welcome to the App!
        </Text>
        <Text
          variant='body'
          style={{
            marginTop: 12,
            textAlign: 'center',
            color: '#64748b',
            lineHeight: 22,
          }}
        >
          You've successfully completed the onboarding process. You can restart
          it anytime using the button below.
        </Text>
      </View>

      <Button
        onPress={resetOnboarding}
        variant='outline'
        style={{ paddingHorizontal: 24 }}
      >
        🔄 Restart Onboarding
      </Button>
    </View>
  );
}

function OnboardingFlow() {
  const { completeOnboarding, skipOnboarding } = useOnboarding();

  const steps: OnboardingStep[] = [
    {
      id: '1',
      title: 'Hook-based State',
      description:
        'This onboarding uses the useOnboarding hook to manage state across your entire app.',
      // icon: '🪝',
    },
    {
      id: '2',
      title: 'Persistent State',
      description:
        'The hook remembers your progress and can be used to control onboarding flow throughout your app.',
      // icon: '📱',
    },
    {
      id: '3',
      title: 'Easy Integration',
      description:
        'Integrate onboarding state with your existing app navigation and user management.',
      // icon: '🚀',
    },
  ];

  return (
    <Onboarding
      steps={steps}
      onComplete={completeOnboarding}
      onSkip={skipOnboarding}
      primaryButtonText='Complete & Continue'
      nextButtonText='Next Step'
      skipButtonText='Skip Demo'
    />
  );
}

export function OnboardingHook() {
  const { hasCompletedOnboarding } = useOnboarding();

  return hasCompletedOnboarding ? <MainApp /> : <OnboardingFlow />;
}
```

## API Reference

### Onboarding

The main onboarding component that manages the multi-step flow.

| Prop                | Type               | Default         | Description                                   |
| ------------------- | ------------------ | --------------- | --------------------------------------------- |
| `steps`             | `OnboardingStep[]` | -               | Array of onboarding steps to display.         |
| `onComplete`        | `() => void`       | -               | Callback when onboarding is completed.        |
| `onSkip`            | `() => void`       | -               | Callback when onboarding is skipped.          |
| `showSkip`          | `boolean`          | `true`          | Whether to show the skip button.              |
| `showProgress`      | `boolean`          | `true`          | Whether to show progress dots.                |
| `swipeEnabled`      | `boolean`          | `true`          | Whether to enable swipe gestures.             |
| `primaryButtonText` | `string`           | `"Get Started"` | Text for the primary button on the last step. |
| `skipButtonText`    | `string`           | `"Skip"`        | Text for the skip button.                     |
| `nextButtonText`    | `string`           | `"Next"`        | Text for the next button.                     |
| `backButtonText`    | `string`           | `"Back"`        | Text for the back button.                     |
| `style`             | `ViewStyle`        | -               | Additional styles for the container.          |
| `children`          | `ReactNode`        | -               | Custom content to render in each step.        |

### OnboardingStep

Configuration object for each step in the onboarding flow.

| Prop              | Type        | Default | Description                                 |
| ----------------- | ----------- | ------- | ------------------------------------------- |
| `id`              | `string`    | -       | Unique identifier for the step.             |
| `title`           | `string`    | -       | Title text for the step.                    |
| `description`     | `string`    | -       | Description text for the step.              |
| `image`           | `ReactNode` | -       | Custom image component for the step.        |
| `icon`            | `ReactNode` | -       | Icon component (used if no image provided). |
| `backgroundColor` | `string`    | -       | Custom background color for the step.       |

### useOnboarding Hook

A hook for managing onboarding state in your application.

```tsx
const {
  hasCompletedOnboarding,
  currentOnboardingStep,
  setCurrentOnboardingStep,
  completeOnboarding,
  resetOnboarding,
  skipOnboarding,
} = useOnboarding();
```

#### Returns

| Property                   | Type                     | Description                                |
| -------------------------- | ------------------------ | ------------------------------------------ |
| `hasCompletedOnboarding`   | `boolean`                | Whether the user has completed onboarding. |
| `currentOnboardingStep`    | `number`                 | Current step index in the onboarding flow. |
| `setCurrentOnboardingStep` | `(step: number) => void` | Function to set the current step.          |
| `completeOnboarding`       | `() => Promise<void>`    | Function to mark onboarding as completed.  |
| `resetOnboarding`          | `() => void`             | Function to reset onboarding state.        |
| `skipOnboarding`           | `() => Promise<void>`    | Function to skip and complete onboarding.  |

## Features

- **Smooth Animations**: Built with react-native-reanimated for fluid transitions
- **Gesture Support**: Swipe left/right to navigate between steps
- **Customizable**: Extensive customization options for styling and behavior
- **Progress Indicators**: Visual progress dots to show current step
- **Flexible Content**: Support for images, icons, and custom content
- **State Management**: Built-in hook for managing onboarding state
- **Accessibility**: Built with accessibility features in mind
- **TypeScript**: Full TypeScript support with proper type definitions

## Accessibility

The Onboarding component is built with accessibility in mind:

- Announces each step change via `AccessibilityInfo.announceForAccessibility` ("<title>. Step X of Y.")
- The decorative progress dots are hidden from the accessibility tree
