While building a feature recently, I hit a limitation.
I needed:
π¨ Fully customizable header & footer
π΅ Circular crop (for profile images)
βοΈ Free-style cropping
π¦ Base64 + file output
π Theme control
π± Consistent behavior on Android & iOS
Most crop libraries either:
- Donβt allow UI customization
- Lock you into native toolbar
- Or donβt give proper base64 support
So I built:
β¨ Why Another Crop Library?
Typical problems I faced:
β No custom header design
β No footer button layout control
β Hard to match app branding
β Limited icon customization
β Poor theme control
I wanted something production-ready with deep customization β so I created this package.
Demo
Android Screenshot
iOS Screenshot
π¦ Installation
yarn add react-native-customizable-image-crop-picker
For iOS
cd ios && pod install
π Complete Working Example
Hereβs a clean implementation:
import React, { useState } from 'react';
import {
Image,
Pressable,
StatusBar,
StyleSheet,
Text,
View,
} from 'react-native';
import { openImageCropPicker } from 'react-native-customizable-image-crop-picker';
const App = () => {
const uploadIconUri = require('../../../upload.jpg');
const [image, setImage] = useState('');
const [base64Image, setBase64Image] = useState('');
const commonOptions = {
cropWidth: 1,
cropHeight: 1,
includeBase64: true,
compressQuality: 0.8,
compressFormat: 'jpeg',
circularCrop: true,
freeStyleCropEnabled: true,
cropGridEnabled: true,
showNativeCropControls: false,
headerTitle: 'Preview',
footerButtonLayout: 'vertical',
footerButtonOrder: 'uploadFirst',
topLeftControl: 'upload',
topRightControl: 'cancel',
cancelText: 'Cancel',
uploadText: 'Upload',
uploadButtonIconUri: uploadIconUri,
};
const open = async (source) => {
try {
const res = await openImageCropPicker({
source,
...commonOptions,
});
const uri = res?.path ? `file://${res.path}` : '';
setImage(uri);
setBase64Image(res?.base64);
} catch (e) {
console.log('Crop failed', e);
}
};
return (
<View style={styles.container}>
<StatusBar barStyle="dark-content" />
<Pressable onPress={() => open('camera')}>
<Text>Camera</Text>
</Pressable>
<Pressable onPress={() => open('gallery')}>
<Text>Gallery</Text>
</Pressable>
<Image source={{ uri: image }} style={{ width: 150, height: 150 }} />
<Image
source={{ uri: `data:image/jpeg;base64,${base64Image}` }}
style={{ width: 150, height: 150 }}
/>
</View>
);
};
export default App;
π― Key Features
π΅ Circular Crop (Perfect for Profile Pictures)
circularCrop: true
βοΈ Free Style Cropping
freeStyleCropEnabled: true
Let users resize crop area freely.
π¨ Fully Custom Header
You can customize:
- Background color
- Title
- Alignment
- Padding
- Height
- Font styling
π Fully Custom Footer Buttons
Control:
- Layout (horizontal / vertical)
- Button order
- Icons (local or remote)
- Icon size
- Tint color
- Padding
- Border radius
You are not locked into default native UI anymore.
π Native Controls (Optional)
If you prefer native system crop toolbar:
showNativeCropControls: true
controlsPlacement: 'bottom'
π¦ Output Format
You get structured output:
{
path: string,
width: number,
height: number,
mime: string,
base64?: string
}
Which works perfectly for:
- API uploads
- Firebase Storage
- AWS S3
- Multipart forms
- Instant preview
π± Real World Use Cases
- Profile image upload
- KYC document capture
- E-commerce product listing
- Social media post creation
- Avatar builders
- Custom design tools
π What Makes This Different?
Instead of forcing native UI, this gives you:
β UI-level customization
β Native performance
β Circular + freestyle crop
β Header/Footer full control
β Clean base64 output
β Android + iOS support
π Final Thoughts
If you're building a production React Native app and want:
- Full branding control
- Clean UX
- No native UI limitations
- Proper base64 support
This package is built for that exact use case.
If this helped you, consider:
π¬ Sharing feedback
π Reporting improvements



Top comments (0)