- Overview
- Installation
- Quick Start
- API Reference
- Configuration Options
- Platform Setup
- Advanced Features
- Examples
- Troubleshooting
A powerful, easy-to-use video and audio trimming library for React Native applications.
- 📹 Video & Audio Support - Trim both video and audio files
- 🌐 Local & Remote Files - Support for local storage and HTTPS URLs
- 💾 Multiple Save Options - Photos, Documents, or Share to other apps
- ✅ File Validation - Built-in validation for media files
- 🗂️ File Management - List, clean up, and delete specific files
- 🔄 Universal Architecture - Works with both New and Old React Native architectures
Feature | Description |
---|---|
Trimming | Precise video/audio trimming with visual controls |
Validation | Check if files are valid video/audio before processing |
Save Options | Photos, Documents, Share sheet integration |
File Management | Complete file lifecycle management |
Customization | Extensive UI and behavior customization |
npm install react-native-video-trim
# or
yarn add react-native-video-trim
📱 iOS Setup (React Native CLI)
npx pod-install ios
Permissions Required:
- For saving to Photos: Add
NSPhotoLibraryUsageDescription
toInfo.plist
🤖 Android Setup (React Native CLI)
For New Architecture:
cd android && ./gradlew generateCodegenArtifactsFromSchema
Permissions Required:
- For saving to Photos: Add to
AndroidManifest.xml
:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
For Share Sheet functionality, add to AndroidManifest.xml
:
<application>
<!-- your other configs -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
Create android/app/src/main/res/xml/file_paths.xml
:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="internal_files" path="." />
<external-path name="external_files" path="." />
</paths>
🔧 Expo Setup
npx expo prebuild
Then rebuild your app. Note: Expo Go may not work due to native dependencies - use development builds or expo run:ios
/expo run:android
.
Get up and running in 3 simple steps:
import { showEditor } from 'react-native-video-trim';
// 1. Basic usage - open video editor
showEditor(videoUrl);
// 2. With duration limit
showEditor(videoUrl, {
maxDuration: 20,
});
// 3. With save options
showEditor(videoUrl, {
maxDuration: 30,
saveToPhoto: true,
openShareSheetOnFinish: true,
});
import { showEditor } from 'react-native-video-trim';
import { launchImageLibrary } from 'react-native-image-picker';
const trimVideo = () => {
// Pick a video
launchImageLibrary({ mediaType: 'video' }, (response) => {
if (response.assets && response.assets[0]) {
const videoUri = response.assets[0].uri;
// Open editor
showEditor(videoUri, {
maxDuration: 60, // 60 seconds max
saveToPhoto: true,
});
}
});
};
💡 More Examples: Check the example folder for complete implementation details with event listeners for both New and Old architectures.
Opens the video trimmer interface.
showEditor(videoPath: string, config?: EditorConfig): void
Parameters:
videoPath
(string): Path to video file (local or remote HTTPS URL)config
(EditorConfig, optional): Configuration options (see Configuration Options)
Example:
showEditor('/path/to/video.mp4', {
maxDuration: 30,
saveToPhoto: true,
});
Programmatically trim a video without showing the UI.
trim(url: string, options: TrimOptions): Promise<string>
Returns: Promise resolving to the output file path
Example:
const outputPath = await trim('/path/to/video.mp4', {
startTime: 5000, // 5 seconds
endTime: 25000, // 25 seconds
});
Method | Description | Returns |
---|---|---|
isValidFile(videoPath) |
Check if file is valid video/audio | Promise<boolean> |
listFiles() |
List all generated output files | Promise<string[]> |
cleanFiles() |
Delete all generated files | Promise<number> |
deleteFile(filePath) |
Delete specific file | Promise<boolean> |
closeEditor() |
Close the editor interface | void |
Examples:
// Validate file before processing
const isValid = await isValidFile('/path/to/video.mp4');
if (!isValid) {
console.log('Invalid video file');
return;
}
// Clean up generated files
const deletedCount = await cleanFiles();
console.log(`Deleted ${deletedCount} files`);
All configuration options are optional. Here are the most commonly used ones:
Option | Type | Default | Description |
---|---|---|---|
type |
'video' | 'audio' |
'video' |
Media type to trim |
outputExt |
string |
'mp4' |
Output file extension |
maxDuration |
number |
video duration |
Maximum duration in milliseconds |
minDuration |
number |
1000 |
Minimum duration in milliseconds |
autoplay |
boolean |
false |
Auto-play media on load |
jumpToPositionOnLoad |
number |
- | Initial position in milliseconds |
Option | Type | Default | Description |
---|---|---|---|
saveToPhoto |
boolean |
false |
Save to photo gallery (requires permissions) |
openDocumentsOnFinish |
boolean |
false |
Open document picker when done |
openShareSheetOnFinish |
boolean |
false |
Open share sheet when done |
removeAfterSavedToPhoto |
boolean |
false |
Delete file after saving to photos |
removeAfterFailedToSavePhoto |
boolean |
false |
Delete file if saving to photos fails |
removeAfterSavedToDocuments |
boolean |
false |
Delete file after saving to documents |
removeAfterFailedToSaveDocuments |
boolean |
false |
Delete file if saving to documents fails |
removeAfterShared |
boolean |
false |
Delete file after sharing (iOS only) |
removeAfterFailedToShare |
boolean |
false |
Delete file if sharing fails (iOS only) |
Option | Type | Default | Description |
---|---|---|---|
cancelButtonText |
string |
"Cancel" |
Cancel button text |
saveButtonText |
string |
"Save" |
Save button text |
trimmingText |
string |
"Trimming video..." |
Progress dialog text |
headerText |
string |
- | Header text |
headerTextSize |
number |
16 |
Header text size |
headerTextColor |
string |
- | Header text color |
trimmerColor |
string |
- | Trimmer bar color |
handleIconColor |
string |
- | Trimmer left/right handles color |
fullScreenModalIOS |
boolean |
false |
Use fullscreen modal on iOS |
Cancel Dialog
Option | Type | Default | Description |
---|---|---|---|
enableCancelDialog |
boolean |
true |
Show confirmation dialog on cancel |
cancelDialogTitle |
string |
"Warning!" |
Cancel dialog title |
cancelDialogMessage |
string |
"Are you sure want to cancel?" |
Cancel dialog message |
cancelDialogCancelText |
string |
"Close" |
Cancel dialog cancel button text |
cancelDialogConfirmText |
string |
"Proceed" |
Cancel dialog confirm button text |
Save Dialog
Option | Type | Default | Description |
---|---|---|---|
enableSaveDialog |
boolean |
true |
Show confirmation dialog on save |
saveDialogTitle |
string |
"Confirmation!" |
Save dialog title |
saveDialogMessage |
string |
"Are you sure want to save?" |
Save dialog message |
saveDialogCancelText |
string |
"Close" |
Save dialog cancel button text |
saveDialogConfirmText |
string |
"Proceed" |
Save dialog confirm button text |
Trimming Cancel Dialog
Option | Type | Default | Description |
---|---|---|---|
enableCancelTrimming |
boolean |
true |
Enable cancel during trimming |
cancelTrimmingButtonText |
string |
"Cancel" |
Cancel trimming button text |
enableCancelTrimmingDialog |
boolean |
true |
Show cancel trimming confirmation |
cancelTrimmingDialogTitle |
string |
"Warning!" |
Cancel trimming dialog title |
cancelTrimmingDialogMessage |
string |
"Are you sure want to cancel trimming?" |
Cancel trimming dialog message |
cancelTrimmingDialogCancelText |
string |
"Close" |
Cancel trimming dialog cancel button |
cancelTrimmingDialogConfirmText |
string |
"Proceed" |
Cancel trimming dialog confirm button |
Error Dialog
Option | Type | Default | Description |
---|---|---|---|
alertOnFailToLoad |
boolean |
true |
Show alert dialog on load failure |
alertOnFailTitle |
string |
"Error" |
Error dialog title |
alertOnFailMessage |
string |
"Fail to load media..." |
Error dialog message |
alertOnFailCloseText |
string |
"Close" |
Error dialog close button text |
Option | Type | Default | Description |
---|---|---|---|
enableHapticFeedback |
boolean |
true |
Enable haptic feedback |
closeWhenFinish |
boolean |
true |
Close editor when done |
enableRotation |
boolean |
false |
Enable video rotation |
rotationAngle |
number |
0 |
Rotation angle in degrees |
changeStatusBarColorOnOpen |
boolean |
false |
Change status bar color (Android only) |
zoomOnWaitingDuration |
number |
5000 |
Duration for zoom-on-waiting feature in milliseconds (default: 5000) |
showEditor(videoPath, {
// Basic settings
maxDuration: 60000,
minDuration: 3000,
// Save options
saveToPhoto: true,
openShareSheetOnFinish: true,
removeAfterSavedToPhoto: true,
// UI customization
headerText: "Trim Your Video",
cancelButtonText: "Back",
saveButtonText: "Done",
trimmerColor: "#007AFF",
// Behavior
autoplay: true,
enableCancelTrimming: true,
});
You can override SDK versions in android/build.gradle
:
buildscript {
ext {
VideoTrim_kotlinVersion = '2.0.21'
VideoTrim_minSdkVersion = 24
VideoTrim_targetSdkVersion = 34
VideoTrim_compileSdkVersion = 35
VideoTrim_ndkVersion = '27.1.12297006'
}
}
For audio-only trimming, specify the media type and output format:
showEditor(audioUrl, {
type: 'audio', // Enable audio mode
outputExt: 'wav', // Output format (mp3, wav, m4a, etc.)
maxDuration: 30000, // 30 seconds max
});
To trim remote files, you need the HTTPS-enabled version of FFmpeg:
Android:
// android/build.gradle
buildscript {
ext {
VideoTrim_ffmpeg_package = 'https'
// Optional: VideoTrim_ffmpeg_version = '6.0.1'
}
}
iOS:
FFMPEGKIT_PACKAGE=https FFMPEG_KIT_PACKAGE_VERSION=6.0 pod install
Usage:
showEditor('https://example.com/video.mp4', {
maxDuration: 60000,
});
Rotate videos during trimming using metadata (doesn't re-encode):
showEditor(videoUrl, {
enableRotation: true,
rotationAngle: 90, // 90, 180, 270 degrees
});
Note: Uses display_rotation
metadata - playback may vary by platform/player.
Users can cancel trimming while in progress:
showEditor(videoUrl, {
enableCancelTrimming: true,
cancelTrimmingButtonText: "Stop",
trimmingText: "Processing video...",
});
Handle loading errors gracefully:
showEditor(videoUrl, {
alertOnFailToLoad: true,
alertOnFailTitle: "Oops!",
alertOnFailMessage: "Cannot load this video file",
alertOnFailCloseText: "OK",
});
import React, { useEffect, useRef } from 'react';
import { TouchableOpacity, Text, View } from 'react-native';
import { showEditor, isValidFile, type Spec } from 'react-native-video-trim';
import { launchImageLibrary } from 'react-native-image-picker';
export default function VideoTrimmer() {
const listeners = useRef({});
useEffect(() => {
// Set up event listeners
listeners.current.onFinishTrimming = (NativeVideoTrim as Spec)
.onFinishTrimming(({ outputPath, startTime, endTime, duration }) => {
console.log('Trimming completed:', {
outputPath,
startTime,
endTime,
duration
});
});
listeners.current.onError = (NativeVideoTrim as Spec)
.onError(({ message, errorCode }) => {
console.error('Trimming error:', message, errorCode);
});
return () => {
// Cleanup listeners
Object.values(listeners.current).forEach(listener =>
listener?.remove()
);
};
}, []);
const selectAndTrimVideo = async () => {
const result = await launchImageLibrary({
mediaType: 'video',
quality: 1,
});
if (result.assets?.[0]?.uri) {
const videoUri = result.assets[0].uri;
// Validate file first
const isValid = await isValidFile(videoUri);
if (!isValid) {
console.log('Invalid video file');
return;
}
// Open editor
showEditor(videoUri, {
maxDuration: 60000, // 1 minute max
saveToPhoto: true, // Save to gallery
openShareSheetOnFinish: true,
headerText: "Trim Video",
trimmerColor: "#007AFF",
});
}
};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<TouchableOpacity
onPress={selectAndTrimVideo}
style={{
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8
}}
>
<Text style={{ color: 'white', fontSize: 16 }}>
Select & Trim Video
</Text>
</TouchableOpacity>
</View>
);
}
import React, { useEffect } from 'react';
import { NativeEventEmitter, NativeModules } from 'react-native';
import { showEditor } from 'react-native-video-trim';
export default function VideoTrimmer() {
useEffect(() => {
const eventEmitter = new NativeEventEmitter(NativeModules.VideoTrim);
const subscription = eventEmitter.addListener('VideoTrim', (event) => {
switch (event.name) {
case 'onFinishTrimming':
console.log('Video trimmed:', event.outputPath);
break;
case 'onError':
console.error('Trimming failed:', event.message);
break;
// Handle other events...
}
});
return () => subscription.remove();
}, []);
// Rest of implementation...
}
Android Build Errors:
- Ensure
file_paths.xml
exists for share functionality - Check SDK versions match your project requirements
- Verify permissions in
AndroidManifest.xml
iOS Build Errors:
- Run
pod install
after installation - Check Info.plist permissions for photo access
- Use development builds with Expo (not Expo Go)
Runtime Issues:
- Validate files with
isValidFile()
before processing - Use HTTPS version for remote files
- Check network connectivity for remote files
- Ensure proper permissions for save operations
- Use
trim()
for batch processing without UI - Clean up generated files regularly with
cleanFiles()
- Consider file compression for large videos
- Android: Based on Android-Video-Trimmer
- iOS: UI from VideoTrimmerControl