These six libraries provide image cropping functionality across different JavaScript frameworks. cropperjs is the framework-agnostic core library that powers several wrappers. ngx-image-cropper is built specifically for Angular applications. react-easy-crop and react-image-crop serve the React ecosystem with different approaches to canvas manipulation. vue-cropper and vue-cropperjs offer cropping solutions for Vue, with one being a native component and the other a wrapper around the core library. Together, they cover the major frontend frameworks with varying levels of customization and ease of use.
Selecting the right image cropping tool depends heavily on your framework and the level of control you need over the canvas. While cropperjs serves as the foundational engine for many solutions, framework-specific wrappers like ngx-image-cropper, react-easy-crop, and Vue variants offer varying degrees of abstraction. Let's compare how they handle integration, output generation, and user interaction.
cropperjs is pure JavaScript and works anywhere.
// cropperjs: Manual initialization
const image = document.getElementById('image');
const cropper = new Cropper(image, {
aspectRatio: 16 / 9,
});
ngx-image-cropper is built for Angular.
<!-- ngx-image-cropper: Angular template -->
<image-cropper
[imageChangedEvent]="imageChangedEvent"
[maintainAspectRatio]="true"
(imageCropped)="imageCropped($event)">
</image-cropper>
react-easy-crop is a React component.
// react-easy-crop: React state management
const [crop, setCrop] = useState({ x: 0, y: 0 });
const [zoom, setZoom] = useState(1);
<Cropper image={imgSrc} crop={crop} zoom={zoom} onCropChange={setCrop} />
react-image-crop is also a React component.
Crop object that you use to draw on a canvas.// react-image-crop: Crop object state
const [crop, setCrop] = useState();
const [completedCrop, setCompletedCrop] = useState();
<ReactCrop crop={crop} onChange={c => setCrop(c)} onComplete={c => setCompletedCrop(c)} />
vue-cropper is a native Vue component.
getCropData via refs.<!-- vue-cropper: Vue template with ref -->
<vue-cropper ref="cropper" :img="img" :outputSize="1"></vue-cropper>
<script>
this.$refs.cropper.getCropData(data => { /* handle data */ });
</script>
vue-cropperjs wraps the vanilla library for Vue.
cropperjs options as Vue props.<!-- vue-cropperjs: Props mirror vanilla options -->
<vue-cropper
ref="cropper"
:src="imgSrc"
:options="{ aspectRatio: 16/9 }"
@ready="onReady"
/>
How you get the final image varies significantly between these tools.
cropperjs generates the image directly.
getCroppedCanvas() to get an HTMLCanvasElement.// cropperjs: Direct canvas output
const canvas = cropper.getCroppedCanvas();
const imageUrl = canvas.toDataURL();
ngx-image-cropper emits the result automatically.
(imageCropped) event fires with the result.// ngx-image-cropper: Event output
imageCropped(event: ImageCroppedEvent) {
this.croppedImage = event.base64; // or event.blob
}
react-easy-crop returns coordinates.
onCropComplete gives you the crop area in pixels.// react-easy-crop: Coordinate output
const onCropComplete = useCallback((croppedArea, croppedAreaPixels) => {
const canvas = createImage(imgSrc, croppedAreaPixels);
}, []);
react-image-crop returns a crop object.
Crop state to draw on a canvas manually.// react-image-crop: Manual canvas drawing
const canvasRef = useRef(null);
// ... inside effect
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
// Draw logic using completedCrop
vue-cropper provides methods for output.
getCropData returns base64 string directly.getCropBlob returns a blob object for uploads.<!-- vue-cropper: Method calls -->
<template>
<button @click="submit">Upload</button>
</template>
<script>
submit() {
this.$refs.cropper.getCropBlob(blob => { /* upload blob */ });
}
</script>
vue-cropperjs accesses the underlying instance.
cropper instance.cropperjs API.<!-- vue-cropperjs: Accessing instance -->
<script>
const getCroppedImage = () => {
const canvas = this.$refs.cropper.cropper.getCroppedCanvas();
};
</script>
Mobile interaction is critical for user-facing apps.
cropperjs has basic touch support.
// cropperjs: Touch configuration
new Cropper(image, {
touchDragZoom: true,
responsive: true
});
ngx-image-cropper relies on the browser.
<!-- ngx-image-cropper: Standard inputs -->
<image-cropper [imageChangedEvent]="event"></image-cropper>
react-easy-crop excels at touch gestures.
// react-easy-crop: Gesture ready
<Cropper
image={img}
crop={crop}
zoom={zoom}
onZoomChange={setZoom}
/>
react-image-crop supports touch basics.
// react-image-crop: Basic touch
<ReactCrop
crop={crop}
onChange={setCrop}
onComplete={setCompletedCrop}
/>
vue-cropper includes touch optimization.
<!-- vue-cropper: Touch features -->
<vue-cropper
:img="img"
:canMove="true"
:canMoveBox="true"
/>
vue-cropperjs inherits cropperjs touch.
<!-- vue-cropperjs: Inherited options -->
<vue-cropper :options="{ touchDragZoom: true }" />
Users need to zoom, rotate, and adjust their photo on mobile.
react-easy-crop or vue-cropper// react-easy-crop example
<Cropper image={avatar} crop={crop} rotation={rotation} />
Staff need to crop scanned documents quickly on desktop.
ngx-image-cropper or react-image-crop<!-- ngx-image-cropper example -->
<image-cropper [maintainAspectRatio]="true" />
You are building a complex editor with filters and layers.
cropperjs// cropperjs example
const cropper = new Cropper(image, { ready: initFilters });
| Package | Framework | Output Type | Touch Support | Complexity |
|---|---|---|---|---|
cropperjs | Vanilla | Canvas | Basic | Medium |
ngx-image-cropper | Angular | Base64/Blob | Basic | Low |
react-easy-crop | React | Coordinates | Advanced | Medium |
react-image-crop | React | Coordinates | Basic | Low |
vue-cropper | Vue | Base64/Blob | Advanced | Low |
vue-cropperjs | Vue | Canvas | Basic | Medium |
Think about your users and your stack:
react-easy-crop or vue-cropper offer the best gesture support.ngx-image-cropper is the only native choice here.cropperjs gives you the raw engine without abstraction.react-image-crop is lightweight and stable for desktop tools.Final Thought: All these tools solve the same problem but optimize for different workflows. Pick the one that matches your framework first, then choose based on how much your users need to manipulate the image on touch devices.
Choose cropperjs if you need a framework-agnostic solution or are working with vanilla JavaScript. It offers the most control over the cropping canvas and has a stable API that other wrappers build upon. This is the best choice for projects that might migrate frameworks or require a custom integration without framework overhead.
Choose ngx-image-cropper if you are building an Angular application and want tight integration with Angular forms and change detection. It simplifies the process by handling the file input and cropping logic within a single component. This saves time on boilerplate code and ensures compatibility with Angular's ecosystem.
Choose react-easy-crop if you prioritize a modern, touch-friendly UI with zooming and rotating capabilities out of the box. It separates the UI interaction from the actual image processing, giving you flexibility in how you generate the final image. This is ideal for mobile-first applications where gesture support is critical.
Choose react-image-crop if you need a lightweight, customizable React component that gives you direct access to the crop coordinates. It is a mature library that works well for standard desktop cropping tasks where advanced gestures are less important. This fits well in admin dashboards or content management systems.
Choose vue-cropper if you are using Vue and want a feature-rich component that handles previewing and cropping in one place. It includes built-in methods for generating base64 or blob outputs directly. This is suitable for Vue projects that need a quick, all-in-one solution without managing external canvas logic.
Choose vue-cropperjs if you prefer the cropperjs API but need Vue bindings for reactivity. It allows you to use the familiar cropperjs options within a Vue component structure. However, verify its maintenance status against your Vue version, as wrappers can sometimes lag behind the core library updates.
JavaScript image cropper.
dist/
├── cropper.js (UMD, bundled)
├── cropper.min.js (UMD, bundled, compressed)
├── cropper.raw.js (UMD, unbundled, default)
├── cropper.esm.js (ECMAScript Module, bundled)
├── cropper.esm.min.js (ECMAScript Module, bundled, compressed)
├── cropper.esm.raw.js (ECMAScript Module, unbundled)
└── cropper.d.ts (TypeScript Declaration File)
npm install cropperjs
import Cropper from 'cropperjs';
const image = new Image();
image.src = '/path/to/image.jpg';
const cropper = new Cropper(image);
Maintained under the Semantic Versioning guidelines.