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.
Modal Components
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);
return (
<Modal visible={visible} onRequestClose={() => setVisible(false)}>
<GestureViewer
data={images}
renderItem={renderImage}
ListComponent={FlatList}
onDismiss={() => setVisible(false)}
/>
</Modal>
);
}
import { FlatList, Image } from 'react-native';
import Modal from 'react-native-modal';
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
const images = [...];
const [visible, setVisible] = useState(false);
return (
<Modal
isVisible={visible}
onBackButtonPress={() => setVisible(false)}
onBackdropPress={() => setVisible(false)}
hasBackdrop={false}
style={styles.modal}
useNativeDriver={true}
hideModalContentWhileAnimating={true}
animationInTiming={300}
animationOutTiming={300}
>
<GestureViewer
data={images}
renderItem={renderImage}
ListComponent={FlatList}
onDismiss={() => setVisible(false)}
/>
</Modal>
);
}
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 { useCallback } from 'react';
import { Image } from 'expo-image';
import { ScrollView } from 'react-native';
import { GestureViewer } from 'react-native-gesture-image-viewer';
const images = [
'https://images.unsplash.com/photo-1682687220742-aba13b6e50ba',
'https://images.unsplash.com/photo-1682687220063-4742bd7fd538',
'https://images.unsplash.com/photo-1682687218147-9806132dc697',
];
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} ListComponent={ScrollView} />;
}
For accurate zoom and pan bounds with contain content, see the item dimensions guide.
renderItem active state (isActive)
For content such as video that should play or perform work only while it is visible, use isActive from the third renderItem argument. It is true only for the currently selected content. During a page transition, the previous content remains active; when the move finishes, the newly selected content becomes active. Use useGestureViewerState instead when UI outside the item needs the global currentIndex.
import type { GestureViewerRenderItemInfo } from 'react-native-gesture-image-viewer';
function renderMedia(item: MediaItem, _index: number, { isActive }: GestureViewerRenderItemInfo) {
return (
<Video
source={{ uri: item.uri }}
style={{ width: '100%', height: '100%' }}
paused={!isActive}
resizeMode="contain"
/>
);
}
return <GestureViewer data={mediaItems} renderItem={renderMedia} />;