β¨ Compound Pattern - Clean, intuitive API with HeroCarousel.Provider, HeroCarousel.Item, and HeroCarousel.AnimatedView
β¨ Context-Based Configuration - All carousel settings are configured through the provider for a clean, centralized API.
β¨ Auto-scrolling with customizable intervals
π Infinite scrolling with seamless transitions
π¬ Video support with play/pause controls
β±οΈ Timer-based pagination with visual progress indicators
π― Advanced animations using React Native Reanimated
π± Gesture-friendly with swipe navigation
π¨ Highly customizable with interpolation utilities
β‘ Performance optimized with worklet functions
npm install @strv/react-native-hero-carousel # or yarn add @strv/react-native-hero-carousel # or pnpm add @strv/react-native-hero-carousel
This library requires the following peer dependencies:
npm install react-native-reanimated react-native-gesture-handler
Make sure to follow the React Native Reanimated installation guide for your platform.
import React from 'react' import { View, Text, StyleSheet } from 'react-native' import { HeroCarousel } from '@strv/react-native-hero-carousel' const slides = [ { id: 1, title: 'Slide 1', color: '#FF6B6B' }, { id: 2, title: 'Slide 2', color: '#4ECDC4' }, { id: 3, title: 'Slide 3', color: '#45B7D1' }, { id: 4, title: 'Slide 4', color: '#96CEB4' }, ] const Slide = ({ title, color }: { title: string; color: string }) => ( <View style={[styles.slide, { backgroundColor: color }]}> <Text style={styles.title}>{title}</Text> </View> ) export default function BasicCarousel() { return ( <HeroCarousel.Provider interval={4000} disableAutoScroll={false} initialIndex={0}> <View style={styles.container}> <HeroCarousel> {slides.map((slide) => ( <Slide key={slide.id} title={slide.title} color={slide.color} /> ))} </HeroCarousel> </View> </HeroCarousel.Provider> ) } const styles = StyleSheet.create({ container: { flex: 1, }, slide: { flex: 1, justifyContent: 'center', alignItems: 'center', }, title: { fontSize: 24, fontWeight: 'bold', color: 'white', }, })
The HeroCarousel component uses a compound pattern that provides a clean, intuitive API:
<HeroCarousel.Provider> <HeroCarousel> <HeroCarousel.Item>{/* Your slide content */}</HeroCarousel.Item> </HeroCarousel> </HeroCarousel.Provider>
The context provider that must wrap your carousel components. All carousel configuration is passed here.
<HeroCarousel.Provider initialIndex={0} // Initial slide index (default: 0) slideWidth={screenWidth} // Width of each slide (default: screen width) interval={3000} // Auto-scroll interval in ms disableAutoScroll={false} // Disable auto-scrolling disableInfiniteScroll={false} // Disable infinite scrolling autoScrollAnimation={(to, duration) => withTiming(to, { duration })} // Custom animation > {children} </HeroCarousel.Provider>
Props:
| Prop | Type | Default | Description |
|---|---|---|---|
initialIndex |
number |
0 |
Initial slide index to start from |
slideWidth |
number |
screen width | Width of each slide in pixels |
interval |
number | ((index: number) => number) |
3000 |
Auto-scroll interval in milliseconds, or function returning interval for each slide |
disableAutoScroll |
boolean |
false |
Disable automatic scrolling |
disableInfiniteScroll |
boolean |
false |
Disable infinite scrolling (shows first/last slide boundaries) |
autoScrollAnimation |
(to: number, duration: number) => number |
withTiming |
Custom animation function for auto-scroll transitions |
children |
React.ReactNode |
Required | Carousel content (should contain HeroCarousel component) |
The main carousel component that renders slides. Takes no configuration props - all configuration is handled by the context provider.
<HeroCarousel> {slides.map((slide) => ( <YourSlideComponent key={slide.id} {...slide} /> ))} </HeroCarousel>
Props:
| Prop | Type | Description |
|---|---|---|
children |
React.ReactNode[] |
Array of slide components |
A wrapper component for individual slides. Provides slide context to child components. Note: This is automatically used internally when you pass children to HeroCarousel, but you can use it directly for more control.
<HeroCarousel.Item>{/* Your slide content */}</HeroCarousel.Item>
A specialized animated view component that automatically handles entering/exiting animations based on carousel scroll position. Perfect for creating slide-specific animations.
import { FadeIn, FadeOut } from 'react-native-reanimated' ;<HeroCarousel.AnimatedView entering={FadeIn.duration(400)} exiting={FadeOut.duration(300)} style={styles.animatedContent} > <Text>This animates when the slide becomes active</Text> </HeroCarousel.AnimatedView>
Props:
| Prop | Type | Default | Description |
|---|---|---|---|
children |
React.ReactNode |
Required | Content to animate |
entering |
AnimatedProps<ViewProps>['entering'] |
- | Entering animation (from react-native-reanimated) |
exiting |
AnimatedProps<ViewProps>['exiting'] |
- | Exiting animation (from react-native-reanimated) |
layout |
AnimatedProps<ViewProps>['layout'] |
- | Layout animation (from react-native-reanimated) |
enteringThreshold |
number |
0.99 |
Threshold (0-1) when entering animation should trigger |
exitingThreshold |
number |
0.01 |
Threshold (0-1) when exiting animation should trigger |
keepVisibleAfterExiting |
boolean |
false |
Keep component visible after exiting animation completes |
style |
AnimatedProps<ViewProps>['style'] |
- | Additional styles |
Access the carousel's shared state and controls.
const { scrollValue, timeoutValue, slideWidth, userInteracted, setUserInteracted } = useCarouselContext()
Returns:
scrollValue: Animated value representing current scroll positiontimeoutValue: Animated value for timer progress (0-1)slideWidth: Width of slidesuserInteracted: Boolean indicating if user has interacted with carouselsetUserInteracted: Function to update interaction state
Get the current slide information and auto-scroll controls. Must be used within a slide component (inside HeroCarousel).
const { index, total, runAutoScroll, goToPage } = useAutoCarouselSlideIndex()
Returns:
index: Current slide indextotal: Total number of slidesrunAutoScroll: Function to manually trigger auto-scroll with custom intervalgoToPage: Function to programmatically navigate to a specific slide from another slide
Hook for creating custom slide animations with automatic interpolation based on carousel scroll position. Must be used within a slide component (inside HeroCarousel). Returns a SharedValue that you can use in animated styles.
import { useInterpolateInsideCarousel } from '@strv/react-native-hero-carousel' import Animated, { useAnimatedStyle, interpolate, Extrapolation } from 'react-native-reanimated' const Slide = () => { const progress = useInterpolateInsideCarousel({ valueBefore: 0, // Value for slides before current thisValue: 1, // Value for current slide valueAfter: 0, // Value for slides after current offset: 0.2, // Animation offset (optional) }) const animatedStyle = useAnimatedStyle(() => { return { opacity: progress.value, transform: [ { scale: interpolate(progress.value, [0, 1], [0.8, 1], Extrapolation.CLAMP), }, ], } }) return <Animated.View style={animatedStyle}>{/* Your content */}</Animated.View> }
Returns:
A SharedValue (from useDerivedValue) representing the interpolated progress value (0-1) based on the current slide's position in the carousel. Access the value using .value in animated styles or worklet functions.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
valueBefore |
number |
Required | Value to use for slides before the current slide |
thisValue |
number |
Required | Value to use for the current slide |
valueAfter |
number |
Required | Value to use for slides after the current slide |
offset |
number |
0 |
Animation offset (0-1) to control when the animation starts/ends |
Note: The interpolateInsideCarousel utility function is now internal-only. Use this hook instead for all custom animations. The hook automatically handles the slide context (index, total, scrollValue) internally.
We provide a comprehensive example app showcasing all the carousel features. You can run the examples locally or view the source code:
cd example
yarn install
yarn startThen scan the QR code with Expo Go or run on simulator. See the example app README for detailed setup instructions.
| Example | Description | Source Code |
|---|---|---|
| Basic Carousel | Simple auto-scrolling image carousel | BasicExample.tsx |
| Animated Carousel | Custom animations with scale, rotation, and opacity | AnimatedExample.tsx |
| Video Carousel | Video playback with play/pause controls | VideoCarouselExample.tsx |
| Timer Pagination | Visual progress indicators with custom intervals | TimerPaginationExample.tsx |
| Entering Animation | Advanced slide entrance animations using HeroCarousel.AnimatedView |
EnteringAnimationExample.tsx |
| Offset Example | Custom slide positioning and spacing | OffsetExample.tsx |
- Image Carousels with smooth transitions and auto-scrolling
- Video Integration with
expo-videoand playback controls - Custom Animations using
useInterpolateInsideCarouselhook - Entering/Exiting Animations using
HeroCarousel.AnimatedViewcomponent - Timer-based Pagination with visual progress bars
- Gesture Handling with swipe navigation and user interaction detection
- Performance Optimization with image preloading and memoization
- Compound Pattern - All examples use
HeroCarousel.Providerfor configuration
The library includes several pagination components and examples:
- Basic Pagination - Simple dot indicators showing current slide (
Pagination.tsx) - Timer Pagination - Animated progress bars with customizable intervals (
TimerPagination.tsx) - Custom Pagination - Build your own pagination using
useCarouselContext()hook for access toscrollValueandtimeoutValue
All pagination components automatically sync with the carousel state and support:
- β Real-time updates as slides change
- β Timer progress visualization with animated fill
- β User interaction detection (pause on touch)
- β Custom styling and animations
Different carousel configurations using the compound pattern:
// Basic auto-scrolling carousel <HeroCarousel.Provider interval={3000}> <HeroCarousel>{slides}</HeroCarousel> </HeroCarousel.Provider> // Video carousel without auto-scroll <HeroCarousel.Provider disableAutoScroll> <HeroCarousel>{videoSlides}</HeroCarousel> </HeroCarousel.Provider> // Carousel with custom intervals per slide <HeroCarousel.Provider interval={(index) => (index + 1) * 2000}> <HeroCarousel>{slides}</HeroCarousel> </HeroCarousel.Provider> // Carousel starting from specific slide <HeroCarousel.Provider initialIndex={2} disableInfiniteScroll> <HeroCarousel>{slides}</HeroCarousel> </HeroCarousel.Provider> // Custom slide width and animation <HeroCarousel.Provider slideWidth={300} autoScrollAnimation={(to, duration) => withSpring(to, { damping: 15 })} > <HeroCarousel>{slides}</HeroCarousel> </HeroCarousel.Provider>
The HeroCarousel.AnimatedView component automatically handles entering/exiting animations based on carousel scroll position. Perfect for creating slide-specific animations:
import { HeroCarousel } from '@strv/react-native-hero-carousel' import { FadeIn, FadeOut, SlideInDown } from 'react-native-reanimated' const Slide = ({ title, image }: { title: string; image: string }) => ( <View style={styles.slide}> <Image source={{ uri: image }} style={styles.image} /> {/* Content that animates when slide becomes active */} <HeroCarousel.AnimatedView entering={FadeIn.duration(400)} exiting={FadeOut.duration(300)} style={styles.content} > <Text style={styles.title}>{title}</Text> </HeroCarousel.AnimatedView> {/* Multiple animated views with different timings */} <HeroCarousel.AnimatedView entering={SlideInDown.duration(500).delay(200)} style={styles.subtitle} > <Text>Subtitle with delay</Text> </HeroCarousel.AnimatedView> </View> ) // Usage <HeroCarousel.Provider> <HeroCarousel> {slides.map((slide) => ( <Slide key={slide.id} {...slide} /> ))} </HeroCarousel> </HeroCarousel.Provider>
Key Features:
- Automatically triggers entering animation when slide becomes active
- Triggers exiting animation when slide leaves view
- Supports all Reanimated entering/exiting animations
- Configurable thresholds for animation timing
- Can keep content visible after exiting animation
Control the carousel programmatically using the context:
const CarouselWithControls = () => { const { scrollValue, goToPage } = useCarouselContext() const { runAutoScroll } = useAutoCarouselSlideIndex() const goToNext = () => { runAutoScroll(0) // Immediate transition } const goToSlide = (slideIndex: number) => { goToPage(slideIndex, 500) // Go to slide with 500ms animation } return ( <HeroCarousel.Provider disableAutoScroll> <View> <HeroCarousel>{/* Your slides */}</HeroCarousel> <View style={styles.controls}> <Button title="Previous" onPress={() => goToSlide(scrollValue.value - 1)} /> <Button title="Next" onPress={goToNext} /> </View> </View> </HeroCarousel.Provider> ) }
- Image Optimization: Use optimized image formats and appropriate resolutions
- Preloading: Preload images/videos for smoother transitions
- Memoization: Wrap slide components in
React.memo()when possible - Worklet Functions: Keep animations in worklet functions for 60fps performance
// Good: Memoized slide component const SlideComponent = React.memo(({ data }) => { // Your slide content }) // Good: Preload images useEffect(() => { images.forEach((uri) => Image.prefetch(uri)) }, [])
This library uses a compound component pattern that provides a clean, intuitive API:
<HeroCarousel.Provider> <HeroCarousel> <HeroCarousel.Item> <HeroCarousel.AnimatedView>{/* Your content */}</HeroCarousel.AnimatedView> </HeroCarousel.Item> </HeroCarousel> </HeroCarousel.Provider>
All carousel configuration is passed to the HeroCarousel.Provider rather than individual components. This design provides several benefits:
β
Centralized Configuration - All settings in one place
β
Cleaner Component API - Components focus on rendering, not configuration
β
Easier Testing - Mock context for isolated component testing
β
Flexible Composition - Components like pagination can be placed anywhere within the provider
The compound pattern allows for:
- Intuitive API - Related components are grouped under
HeroCarousel.* - Better Discoverability - All carousel-related components are accessible via autocomplete
- Flexible Usage - Use
HeroCarousel.ItemandHeroCarousel.AnimatedViewwhen needed, or pass children directly toHeroCarousel
Carousel not auto-scrolling:
- Ensure
HeroCarousel.Providerwraps your carousel - Check if
disableAutoScrollis set tofalse - Verify React Native Reanimated is properly installed
Animations not smooth:
- Make sure animations are running in worklet functions
- Use
runOnUIfor heavy computations - Avoid heavy operations in animation callbacks
Infinite scroll not working:
- Ensure you have at least 2 slides
- Check if slide widths are properly configured
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.
MIT License - see the LICENSE file for details.
Built with β€οΈ using:
- React Native Reanimated for animations
- React Native Gesture Handler for gestures
Made by STRV π