A React Native module that allows you to use native UI to select media from the device library or directly from the camera
npx @tessl/cli install tessl/npm-react-native-image-picker@8.2.0React Native Image Picker provides native UI access for selecting photos and videos from device libraries or directly from the camera. It offers cross-platform support for iOS, Android, and web with comprehensive options for media selection including quality control, size constraints, format preferences, and multiple selection capabilities.
npm install react-native-image-pickerimport { launchCamera, launchImageLibrary } from "react-native-image-picker";For CommonJS:
const { launchCamera, launchImageLibrary } = require("react-native-image-picker");import { launchCamera, launchImageLibrary, ImagePickerResponse } from "react-native-image-picker";
// Launch camera to take a photo
const cameraOptions = { mediaType: 'photo' as const, quality: 0.8 };
const cameraResult = await launchCamera(cameraOptions);
if (cameraResult.assets && cameraResult.assets.length > 0) {
const asset = cameraResult.assets[0];
console.log('Image URI:', asset.uri);
}
// Launch image library to select photos
const libraryOptions = { mediaType: 'photo' as const, selectionLimit: 3 };
const libraryResult = await launchImageLibrary(libraryOptions);
if (libraryResult.assets) {
libraryResult.assets.forEach((asset, index) => {
console.log(`Selected image ${index + 1}:`, asset.uri);
});
}React Native Image Picker is built around platform-specific implementations:
launchCamera and launchImageLibrary functions work consistently across platformsPlatform.OSLaunches the device camera to capture photos or videos with extensive configuration options.
/**
* Launch camera to take photo or video
* @param options - Camera configuration options
* @param callback - Optional callback function for response
* @returns Promise resolving to ImagePickerResponse
*/
function launchCamera(
options: CameraOptions,
callback?: Callback
): Promise<ImagePickerResponse>;
interface CameraOptions extends OptionsCommon {
/** Maximum video duration in seconds */
durationLimit?: number;
/** Save captured media to device photos (requires permissions on Android <29) */
saveToPhotos?: boolean;
/** Camera type selection */
cameraType?: CameraType;
}Launches the device image/video library for media selection with support for multiple items and filtering.
/**
* Launch gallery to pick image or video
* @param options - Image library configuration options
* @param callback - Optional callback function for response
* @returns Promise resolving to ImagePickerResponse
*/
function launchImageLibrary(
options: ImageLibraryOptions,
callback?: Callback
): Promise<ImagePickerResponse>;
interface ImageLibraryOptions extends OptionsCommon {
/** Number of items to select (0 = unlimited on iOS ≥14, Android ≥13) */
selectionLimit?: number;
/** Array of allowed MIME types (Android only) */
restrictMimeTypes?: string[];
}interface ImagePickerResponse {
/** True if user cancelled the operation */
didCancel?: boolean;
/** Error code if operation failed */
errorCode?: ErrorCode;
/** Error message for debugging */
errorMessage?: string;
/** Array of selected media assets */
assets?: Asset[];
}
interface Asset {
/** Base64 string of image (photos only, if includeBase64: true) */
base64?: string;
/** File URI in app cache storage */
uri?: string;
/** Asset width in pixels */
width?: number;
/** Asset height in pixels */
height?: number;
/** Original file path (Android only) */
originalPath?: string;
/** File size in bytes */
fileSize?: number;
/** MIME type of the file */
type?: string;
/** Name of the file */
fileName?: string;
/** Video duration in seconds (video only) */
duration?: number;
/** Video bitrate in bits/sec (Android only) */
bitrate?: number;
/** Asset timestamp (requires includeExtra: true) */
timestamp?: string;
/** Local identifier (requires includeExtra: true) */
id?: string;
}interface OptionsCommon {
/** Type of media to select */
mediaType: MediaType;
/** Maximum width for image resizing */
maxWidth?: number;
/** Maximum height for image resizing */
maxHeight?: number;
/** Photo quality level (0-1) */
quality?: PhotoQuality;
/** Video quality setting (platform-specific) */
videoQuality?: AndroidVideoOptions | iOSVideoOptions;
/** Include base64 string in response (avoid for large images) */
includeBase64?: boolean;
/** Include extra metadata requiring permissions */
includeExtra?: boolean;
/** Convert selected video to MP4 (iOS only) */
formatAsMp4?: boolean;
/** Picker presentation style (iOS only) */
presentationStyle?:
| 'currentContext'
| 'fullScreen'
| 'pageSheet'
| 'formSheet'
| 'popover'
| 'overFullScreen'
| 'overCurrentContext';
/** Asset representation mode for HEIC/HEIF handling */
assetRepresentationMode?: 'auto' | 'current' | 'compatible';
}/** Callback function type for picker responses */
type Callback = (response: ImagePickerResponse) => any;
/** Media type selection */
type MediaType = 'photo' | 'video' | 'mixed';
/** Camera type selection */
type CameraType = 'back' | 'front';
/** Photo quality levels */
type PhotoQuality =
| 0 | 0.1 | 0.2 | 0.3 | 0.4 | 0.5
| 0.6 | 0.7 | 0.8 | 0.9 | 1;
/** Video quality options for Android */
type AndroidVideoOptions = 'low' | 'high';
/** Video quality options for iOS */
type iOSVideoOptions = 'low' | 'medium' | 'high';
/** Error codes for failed operations */
type ErrorCode = 'camera_unavailable' | 'permission' | 'others';| Feature | iOS | Android | Web |
|---|---|---|---|
| Photo capture/selection | ✅ | ✅ | ✅ |
| Video capture/selection | ✅ | ✅ | ❌ |
| Multiple selection | ✅ | ✅ | ✅ |
| Quality control | ✅ | ✅ | ❌ |
| Camera type selection | ✅ | ✅ | ❌ |
| Base64 encoding | ✅ | ✅ | ✅ |
| Save to photos | ✅ | ✅ | ❌ |
| MIME type restrictions | ❌ | ✅ | ❌ |
import { launchCamera, CameraOptions } from "react-native-image-picker";
const options: CameraOptions = {
mediaType: 'photo',
quality: 0.8,
maxWidth: 1000,
maxHeight: 1000,
cameraType: 'back',
saveToPhotos: true,
includeBase64: false,
};
try {
const result = await launchCamera(options);
if (result.didCancel) {
console.log('User cancelled camera');
} else if (result.errorMessage) {
console.error('Camera Error:', result.errorMessage);
} else if (result.assets && result.assets[0]) {
const asset = result.assets[0];
console.log('Captured image:', {
uri: asset.uri,
width: asset.width,
height: asset.height,
fileSize: asset.fileSize,
});
}
} catch (error) {
console.error('Camera launch failed:', error);
}import { launchImageLibrary, ImageLibraryOptions } from "react-native-image-picker";
const options: ImageLibraryOptions = {
mediaType: 'photo',
selectionLimit: 5, // Allow up to 5 images
quality: 0.9,
includeBase64: false,
};
const result = await launchImageLibrary(options);
if (result.assets) {
console.log(`Selected ${result.assets.length} images:`);
result.assets.forEach((asset, index) => {
console.log(`Image ${index + 1}:`, {
uri: asset.uri,
fileName: asset.fileName,
fileSize: asset.fileSize,
type: asset.type,
});
});
}import { launchCamera, CameraOptions } from "react-native-image-picker";
const videoOptions: CameraOptions = {
mediaType: 'video',
videoQuality: 'high',
durationLimit: 60, // 60 seconds max
cameraType: 'back',
};
const result = await launchCamera(videoOptions);
if (result.assets && result.assets[0]) {
const video = result.assets[0];
console.log('Recorded video:', {
uri: video.uri,
duration: video.duration,
fileSize: video.fileSize,
type: video.type,
});
}import { launchImageLibrary, ImagePickerResponse } from "react-native-image-picker";
// Using callback instead of await
launchImageLibrary(
{ mediaType: 'photo', selectionLimit: 1 },
(response: ImagePickerResponse) => {
if (response.assets && response.assets[0]) {
console.log('Selected image URI:', response.assets[0].uri);
}
}
);import { launchCamera, ErrorCode } from "react-native-image-picker";
const result = await launchCamera({ mediaType: 'photo' });
if (result.errorCode) {
switch (result.errorCode) {
case 'camera_unavailable':
console.error('Camera not available on this device');
break;
case 'permission':
console.error('Camera permission denied');
break;
case 'others':
console.error('Other error:', result.errorMessage);
break;
}
}