Skip to content

Hooks

For advanced use cases, you can use the individual hooks to build custom implementations.

useSwipeableStack

Manages stack state with imperative controls.

tsx
import { useSwipeableStack } from 'react-native-swipeable-stack';

const {
  currentIndex,
  currentItem,
  nextItem,
  isEmpty,
  swipeLeft,
  swipeRight,
  undo,
} = useSwipeableStack({
  data: items,
  onSwipeRight: (item) => console.log('Liked', item),
  onSwipeLeft: (item) => console.log('Noped', item),
  onEmpty: () => console.log('Stack empty'),
});

Parameters

OptionTypeDescription
dataT[]Array of items
initialIndexnumberStarting index (default: 0)
onSwipeLeft(item: T, index: number) => voidLeft swipe callback
onSwipeRight(item: T, index: number) => voidRight swipe callback
onSwipeComplete(direction, item, index) => voidAny swipe callback
onEmpty() => voidStack empty callback
onIndexChange(index: number) => voidIndex change callback

Return Value

PropertyTypeDescription
currentIndexnumberCurrent card index
currentItemT | undefinedCurrent visible item
nextItemT | undefinedNext item in stack
isEmptybooleanWhether stack is empty
swipeLeft() => voidTrigger left swipe
swipeRight() => voidTrigger right swipe
undo() => voidUndo last swipe

useSwipeGesture

Creates the pan gesture with spring physics.

tsx
import { useSwipeGesture } from 'react-native-swipeable-stack';

const { gesture, translateX, translateY } = useSwipeGesture({
  swipeThreshold: 120,
  velocityThreshold: 800,
  screenWidth: 400,
  verticalFriction: 0.2,
  animationConfig: {
    swipeSpring: { stiffness: 200, damping: 20 },
    returnSpring: { stiffness: 300, damping: 30 },
  },
  onSwipeComplete: (direction) => console.log('Swiped:', direction),
});

Parameters

OptionTypeDescription
swipeThresholdnumberDistance to trigger swipe
velocityThresholdnumberVelocity to trigger swipe
screenWidthnumberScreen width for calculations
verticalFrictionnumberDampens Y movement (0-1)
animationConfigAnimationConfigSpring configurations
onSwipeComplete(direction: SwipeDirection) => voidSwipe callback
disabledbooleanDisable gesture

Return Value

PropertyTypeDescription
gesturePanGestureGesture Handler pan gesture
translateXSharedValue<number>Animated X position
translateYSharedValue<number>Animated Y position

useSwipeAnimation

Creates animated styles for card and overlays.

tsx
import { useSwipeAnimation } from 'react-native-swipeable-stack';

const { 
  animatedCardStyle, 
  leftOverlayStyle, 
  rightOverlayStyle 
} = useSwipeAnimation({
  translateX,
  translateY,
  screenWidth: 400,
  maxRotation: 15,
  overlayConfig: { 
    inputRange: [0, 80], 
    outputRange: [0, 1] 
  },
});

Parameters

OptionTypeDescription
translateXSharedValue<number>X translation value
translateYSharedValue<number>Y translation value
screenWidthnumberScreen width for rotation calc
maxRotationnumberMax rotation in degrees
overlayConfigOverlayConfigOverlay opacity config

Return Value

PropertyTypeDescription
animatedCardStyleAnimatedStyleStyle for card (transform + rotation)
leftOverlayStyleAnimatedStyleStyle for left overlay (opacity)
rightOverlayStyleAnimatedStyleStyle for right overlay (opacity)

useNextCardAnimation

Creates animated style for the background card (scale + opacity).

tsx
import { useNextCardAnimation } from 'react-native-swipeable-stack';

const nextCardStyle = useNextCardAnimation({
  swipeProgress: translateX,
  screenWidth: 400,
});

// Apply to the next card
<Animated.View style={[styles.card, nextCardStyle]}>
  {renderCard(nextItem)}
</Animated.View>

Parameters

OptionTypeDescription
swipeProgressSharedValue<number>Current swipe X position
screenWidthnumberScreen width for interpolation

Return Value

Returns an AnimatedStyle with:

  • scale: Interpolates from 0.92 to 1
  • opacity: Interpolates from 0.6 to 1

Building a Custom Stack

Here's how you might combine these hooks for a fully custom implementation:

tsx
import {
  useSwipeableStack,
  useSwipeGesture,
  useSwipeAnimation,
  useNextCardAnimation,
} from 'react-native-swipeable-stack';

function CustomStack({ data }) {
  const { currentItem, nextItem, swipeLeft, swipeRight } = useSwipeableStack({
    data,
    onSwipeComplete: (dir, item) => console.log(dir, item),
  });

  const { gesture, translateX, translateY } = useSwipeGesture({
    swipeThreshold: 120,
    velocityThreshold: 800,
    screenWidth: SCREEN_WIDTH,
    onSwipeComplete: (direction) => {
      direction === 'left' ? swipeLeft() : swipeRight();
    },
  });

  const { animatedCardStyle } = useSwipeAnimation({
    translateX,
    translateY,
    screenWidth: SCREEN_WIDTH,
    maxRotation: 15,
  });

  const nextCardStyle = useNextCardAnimation({
    swipeProgress: translateX,
    screenWidth: SCREEN_WIDTH,
  });

  return (
    <GestureHandlerRootView>
      {nextItem && (
        <Animated.View style={nextCardStyle}>
          <Card item={nextItem} />
        </Animated.View>
      )}
      <GestureDetector gesture={gesture}>
        <Animated.View style={animatedCardStyle}>
          <Card item={currentItem} />
        </Animated.View>
      </GestureDetector>
    </GestureHandlerRootView>
  );
}

Released under the MIT License.