You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

react-native-gesture-image-viewer

Package Overview
Dependencies
Maintainers
0
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-native-gesture-image-viewer

🖼️ A highly customizable and easy-to-use React Native image viewer with gesture support and external controls

1.6.1
latest
Source
npmnpm
Version published
Maintainers
0
Created
Source

React Native Gesture Image Viewer

English | 한국어

Overview

Have you ever struggled with implementing complex gesture handling and animations when building image galleries or content viewers in React Native?

Existing libraries often have limited customization options or performance issues. react-native-gesture-image-viewer is a high-performance universal gesture viewer library built on React Native Reanimated and Gesture Handler, providing complete customization and intuitive gesture support for not only images but also videos, custom components, and any other content.

Key Features

  • Complete Gesture Support - Pinch zoom, double-tap zoom, swipe navigation, vertical drag dismiss
  • High-Performance Animations - Smooth 60fps animations powered by React Native Reanimated
  • Full Customization - Complete control over components, styles, and behaviors
  • External Control API - Programmatic control from buttons or other components
  • Multi-Instance Management - ID-based independent management of multiple viewers
  • Flexible Integration - Use with Modal, React Native Modal, ScrollView, FlatList, FlashList, Expo Image, FastImage, and more
  • Full TypeScript Support - Enhanced developer experience with smart type inference
  • Cross-Platform - iOS, Android, and Web support
  • Easy-to-Use API - Intuitive and simple implementation without complex setup
  • Various Environment Support - Expo Go and New Architecture support

Quick Start

Examples & Demo

Prerequisites

[!IMPORTANT] react-native-gesture-image-viewer is a high-performance viewer library built on react-native-reanimated and react-native-gesture-handler.
Therefore, you must install React Native Reanimated and Gesture Handler before using this library. Please refer to the official documentation of these libraries for detailed setup guides.

npm install react-native-reanimated
npm install react-native-gesture-handler

Minimum Requirements

LibraryMinimum Version
react>=18.0.0
react-native>=0.75.0
react-native-gesture-handler>=2.24.0
react-native-reanimated>=3.0.0

React Native Reanimated Setup

Add the plugin to your babel.config.js:

// babel.config.js
module.exports = {
  presets: [
    ... // don't add it here :)
  ],
  plugins: [
    ...
    // for web
    '@babel/plugin-proposal-export-namespace-from',
    // react-native-reanimated/plugin has to be listed last.
    'react-native-reanimated/plugin',
  ],
};

Wrap your Metro config with wrapWithReanimatedMetroConfig in metro.config.js:

const {
  wrapWithReanimatedMetroConfig,
} = require('react-native-reanimated/metro-config');

const config = {
  // Your existing Metro configuration options
};

module.exports = wrapWithReanimatedMetroConfig(config);

react-native-gesture-handler Setup

  • react-native-gesture-handler generally doesn't require additional setup, but please refer to the official documentation for your specific environment.
  • For using gestures in Android modals, you would normally need to wrap modal content with GestureHandlerRootView. However, this library already includes GestureHandlerRootView internally, so no additional wrapping is needed when using modals.

Installation

# npm
npm install react-native-gesture-image-viewer

# pnpm
pnpm add react-native-gesture-image-viewer

# yarn
yarn add react-native-gesture-image-viewer

# bun
bun add react-native-gesture-image-viewer

Usage

Basic Usage

react-native-gesture-image-viewer is a library focused purely on gesture interactions for complete customization.
You can create a viewer using any Modal of your choice as shown below:

import { FlatList, Image, Modal } from 'react-native';
import { GestureViewer } from 'react-native-gesture-image-viewer';

function App() {
  const images = [...];
  const [visible, setVisible] = useState(false);

  // Wrap with useCallback for performance optimization
  const renderImage = useCallback((imageUrl: string) => {
    return <Image source={{ uri: imageUrl }} style={{ width: '100%', height: '100%' }} resizeMode="contain" />;
  }, []);

  return (
    <Modal visible={visible} onRequestClose={() => setVisible(false)}>
      <GestureViewer
        data={images}
        renderItem={renderImage}
        ListComponent={FlatList}
        onDismiss={() => setVisible(false)}
      />
    </Modal>
  );
}

Gesture Features

react-native-gesture-image-viewer supports various gestures essential for viewers. All gestures are enabled by default.

function App() {
  return (
    <GestureViewer
      data={images}
      renderItem={renderImage}
      enableLoop={false}
      enableDismissGesture
      enableSwipeGesture
      enableZoomGesture
      enableDoubleTapGesture
      enableZoomPanGesture
    />
  )
}
PropertyDescriptionDefault
enableLoopEnables loop mode. When true, navigating next from the last item goes to the first item, and navigating previous from the first item goes to the last item.false
enableDismissGestureCalls onDismiss function when swiping down. Useful for closing modals with downward swipe gestures.true
enableSwipeGestureControls left/right swipe gestures. When false, horizontal gestures are disabled.true
enableZoomGestureControls two-finger pinch gestures with focal point zooming. When false, pinch zoom is disabled. Zoom centers on the point between your two fingers for intuitive scaling.true
enableDoubleTapGestureControls double-tap zoom gestures with precision targeting. When false, double-tap zoom is disabled. Zoom centers exactly on the tapped location.true
enableZoomPanGestureEnables panning when zoomed in with automatic boundary detection. When false, movement is disabled during zoom. Prevents content from moving outside visible screen area.true

Custom Components

react-native-gesture-image-viewer offers powerful complete component customization. You can create gesture-supported items with not only images but any component you want.

List Components

Support for any list component like ScrollView, FlatList, FlashList through the ListComponent prop.
The listProps provides type inference based on the selected list component, ensuring accurate autocompletion and type safety in your IDE.

import { FlashList } from '@shopify/flash-list';

function App() {
  return (
    <GestureViewer
      data={images}
      ListComponent={FlashList}
      listProps={{
        // ✅ FlashList props autocompletion
      }}
    />
  );
}

Content Components

You can inject various types of content components like expo-image, FastImage, etc., through the renderItem prop to use gestures.

import { GestureViewer } from 'react-native-gesture-image-viewer';
import { Image } from 'expo-image';

function App() {
  const renderImage = useCallback((imageUrl: string) => {
    return <Image source={{ uri: imageUrl }} style={{ width: '100%', height: '100%' }} contentFit="contain" />;
  }, []);

  return (
    <GestureViewer
      data={images}
      renderItem={renderImage}
    />
  );
}

useGestureViewerController

You can programmatically control the GestureViewer using the useGestureViewerController hook.

import { GestureViewer, useGestureViewerController } from 'react-native-gesture-image-viewer';

function App() {
  const {
    goToIndex,
    goToPrevious,
    goToNext,
    currentIndex,
    totalCount,
    zoomIn,
    zoomOut,
    resetZoom,
    rotate
  } = useGestureViewerController();

  return (
    <View>
      <GestureViewer
        data={images}
        renderItem={renderImage}
      />
      {/* Zoom Controls */}
      <View>
        <Feather.Button name="zoom-in" onPress={() => zoomIn(0.25)} />
        <Feather.Button name="zoom-out" onPress={() => zoomOut(0.25)} />
        <Feather.Button
          name="refresh-cw"
          onPress={() => {
            rotate(0);
            resetZoom();
          }}
        />
        <Feather.Button name="rotate-cw" onPress={() => rotate(90)} />
        <Feather.Button name="rotate-ccw" onPress={() => rotate(90, false)} />
      </View>
      {/* Navigation Controls */}
      <View>
        <Feather.Button name="chevron-left" onPress={goToPrevious} />
        <Button title="Jump to index 2" onPress={() => goToIndex(2)} />
        <Feather.Button name="chevron-right" onPress={goToNext} />
        <Text>{`${currentIndex + 1} / ${totalCount}`}</Text>
      </View>
    </View>
  );
}

API Reference

PropertyDescriptionTypeDefault
goToIndexNavigate to a specific index.(index: number) => void-
goToPreviousNavigate to the previous item.() => void-
goToNextNavigate to the next item.() => void-
currentIndexThe index of the currently displayed item.number0
totalCountThe total number of items.number0
zoomInZoom in by the specified multiplier.(multiplier?: number) => void0.25
zoomOutZoom out by the specified multiplier.(multiplier?: number) => void0.25
resetZoomReset zoom to the specified scale.(scale?: number) => void1
rotateRotate by the specified angle.(angle?: number, clockwise?: boolean) => void90, true

Parameters

  • zoomIn(multiplier?)
    • multiplier: The multiplier for zooming in (range: 0.01 ~ 1)
    • Example: zoomIn(0.5) → Zoom in by an additional 50% of the current scale
  • zoomOut(multiplier?)
    • multiplier: The multiplier for zooming out (range: 0.01 ~ 1)
    • Example: zoomOut(0.3) → Zoom out by dividing the current scale by 1.3
  • resetZoom(scale?)
    • scale: The scale value to reset to
    • Example: resetZoom(1.5) → Reset to 1.5x scale
  • rotate(angle?, clockwise?)
    • angle: The angle to rotate (0, 90, 180, 270, 360)
    • clockwise: The direction to rotate (true: clockwise, false: counter-clockwise)
    • Example: rotate(90) → Rotate 90 degrees clockwise
    • Example: rotate(90, false) → Rotate 90 degrees counter-clockwise
    • Example: rotate(0) → Reset rotation

useGestureViewerEvent

You can subscribe to specific events from GestureViewer using the useGestureViewerEvent hook. This allows you to respond to real-time gesture changes like zoom and rotation.

import { GestureViewer, useGestureViewerEvent } from 'react-native-gesture-image-viewer';

function App() {
  // Listen to zoom changes on the default instance (ID: 'default')
  useGestureViewerEvent('zoomChange', (data) => {
    console.log(`Zoom changed from ${data.previousScale} to ${data.scale}`);
  });

  // Listen to rotation changes on the default instance (ID: 'default')
  useGestureViewerEvent('rotationChange', (data) => {
    console.log(`Rotation changed from ${data.previousRotation}° to ${data.rotation}°`);
  });

  // Listen to events on a specific instance
  useGestureViewerEvent('gallery', 'zoomChange', (data) => {
    console.log(`Gallery zoom: ${data.scale}x`);
  });

  return (
    <GestureViewer
      data={images}
      renderItem={renderImage}
    />
  );
}

Event Types

EventDescriptionData
zoomChangeFired when the zoom scale changes during pinch gestures{ scale: number, previousScale: number }
rotationChangeFired when the rotation angle changes during rotation gestures{ rotation: number, previousRotation: number }

Style Customization

You can customize the styling of GestureViewer.

import { GestureViewer } from 'react-native-gesture-image-viewer';

function App() {
  return (
    <GestureViewer
      animateBackdrop={false}
      width={400}
      containerStyle={{ /* ... */ }}
      backdropStyle={{ backgroundColor: 'rgba(0, 0, 0, 0.90)' }}
      renderContainer={(children) => <View style={{ flex: 1 }}>{children}</View>}
    />
  );
}
PropertyDescriptionDefault
animateBackdropBy default, the background opacity gradually decreases from 1 to 0 during downward swipe gestures. When false, this animation is disabled.true
widthThe width of content items. Default is window width.Dimensions width
containerStyleAllows custom styling of the container that wraps the list component.flex: 1
backdropStyleAllows customization of the viewer's background style.backgroundColor: black; StyleSheet.absoluteFill;
renderContainerAllows custom wrapper component around <GestureViewer />.

Multi-Instance Management

When you want to efficiently manage multiple GestureViewer instances, you can use the id prop to use multiple GestureViewer components.
GestureViewer automatically removes instances from memory when components are unmounted, so no manual memory management is required.

The default id value is default.

import { GestureViewer, useGestureViewerController } from 'react-native-gesture-image-viewer';

const firstViewerId = 'firstViewerId';
const secondViewerId = 'secondViewerId';

function App() {
  const { currentIndex: firstCurrentIndex, totalCount: firstTotalCount } = useGestureViewerController(firstViewerId);
  const { currentIndex: secondCurrentIndex, totalCount: secondTotalCount } = useGestureViewerController(secondViewerId);

  return (
    <View>
      <GestureViewer
        id={firstViewerId}
        data={images}
        renderItem={renderImage}
      />
      <GestureViewer
        id={secondViewerId}
        data={images}
        renderItem={renderImage}
      />
    </View>
  );
}

Additional Props

onIndexChange

The onIndexChange callback function is called when the index value changes.

import { GestureViewer } from 'react-native-gesture-image-viewer';

function App() {
  const [currentIndex, setCurrentIndex] = useState(0);

  return (
    <GestureViewer
      onIndexChange={setCurrentIndex}
    />
  );
}

useSnap

Sets the scroll behavior mode. false (default) uses paging mode, true uses snap mode.

import { GestureViewer } from 'react-native-gesture-image-viewer';

function App() {
  return (
    <GestureViewer
      data={data}
      renderItem={renderItem}
      useSnap={true}
    />
  );
}

itemSpacing

Sets the spacing between items in pixels. Only applied when useSnap is true.

import { GestureViewer } from 'react-native-gesture-image-viewer';

function App() {
  return (
    <GestureViewer
      data={data}
      renderItem={renderItem}
      useSnap={true}
      itemSpacing={16} // 16px spacing between items
    />
  );
}

initialIndex (default: 0)

Sets the initial index value.

dismissThreshold (default: 80)

dismissThreshold controls when onDismiss is called by applying a threshold value during vertical gestures.

resistance (default: 2)

resistance controls the range of vertical movement by applying resistance during vertical gestures.

maxZoomScale (default: 2)

Controls the maximum zoom scale multiplier.

Performance Optimization Tips

  • Wrap the renderItem function with useCallback to prevent unnecessary re-renders.
  • For large images, we recommend using FastImage or expo-image.
  • For handling many images, we recommend using FlashList.
  • Test on actual devices (performance may be limited in simulators).

Contributing

For details on how to contribute to the project and set up the development environment, please refer to the Contributing Guide.

License

MIT

Keywords

react-native

FAQs

Package last updated on 30 Jul 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts