Expo Media Preview
A lightweight media viewer that allows full-screen (image/video/GIF).
You can pinch zoom-in/out, double-tap zoom-in/out, move and swipe-to-dismiss.
Note: This library is only compatible with Expo 52 and above
Note: If media is of big quality it will take time to render hence spinner
Features
- Single Tap to open an media full-screen.
- Pinch to Zoom.
- Drag to Dismiss.
- Supports Images, GIFs, and Videos out of the box.
Installation
Using npm:
npm install expo-media-preview
Using yarn:
yarn add expo-media-preview
Additionally, install required peer dependencies:
expo install expo-image expo-video expo-blur
Demo

Quick Start
- Install the package (and its peer dependencies).
- Import and use with either an image or a video source.
import React from "react";
import { View } from "react-native";
import ExpoMediaPreview from "expo-media-preview";
export default function App() {
const sampleImage = {
uri: "https://path-to-your-img-file.jpg", // Replace with your image URL
};
const sampleVideo = {
uri: "https://path-to-your-video-file.mp4", // Replace with your video URL
};
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
{/* Usage with an image */}
<ExpoMediaPreview
source={sampleImage}
style={{
height: 150,
width: 150,
}}
/>
{/* Usage with a video */}
<ExpoMediaPreview
source={sampleVideo}
videoPlaceholderSrc={{
uri: "https://path-to-your-placeholder-image.jpg",
}}
isVideo={true}
style={{
height: 150,
width: 150,
}}
/>
</View>
);
}
Behind the Scenes
- expo-image is used for efficient image loading and caching.
- expo-video powers the video playback.
- Pinch, Zoom, and Drag logic is handled via React Native’s PanResponder.
- expo-blur for background blurring during full-screen mode.
ExpoMediaPreview Component Props
Prop | Type | Description |
---|
source | Undefined | Media source |
videoPlaceholder | ImageSourcePropType | Image source for video placeholder |
isVideo | boolean | Determines if the source is a video default false |
style | StyleProp | Style for the original Media |
swipeToDismiss | boolean | Enable swipe to dismiss functionality |
disabled | boolean | Disable opening image modal |
parentLayout | { x: number, y: number, width: number, height: number } | Parent component layout for modal |
animationDuration | number | Duration of animation default 150 |
onTap | (eventParams: OnTap) => void | Callback when media is tapped |
onDoubleTap | () => void | Callback when media is double tapped |
onLongPress | () => void | Callback when media is long pressed |
onOpen | () => void | Callback when media modal is opening |
didOpen | () => void | Callback when media modal is opened |
onMove | (position: OnMove) => void | Callback when modal media is moving |
responderRelease | (vx: number, scale: number) => void | Callback when touch is released |
willClose | () => void | Callback when media modal is closing |
onClose | () => void | Callback when media modal is closed |
- Video Placeholder (Highly Recommended): Always include
videoPlaceholderSrc
for videos. This uses expo-image
for better quality and caching. Without it, videos render initially muted, paused, and without controls.
Regarding Videos:
Made with ❤️ and Expo
Credits: Inspired from react-native-image-modal