
Cropper.js is a JavaScript image cropping library for adding an interactive crop area to images in the browser. You can drag and resize the crop box, move or rotate the image, zoom, flip, and export the selected region to a canvas.
The latest Cropper.js library (v2.x+) builds the editor from Web Components. Crop geometry lives on <cropper-selection>, image transforms live on <cropper-image>, and pointer actions run through <cropper-canvas>.
The main cropperjs package includes the standard component set, while individual @cropper/* packages are available for custom builds.
Features:
- Draggable and resizable crop selections.
- Fixed and free aspect ratios.
- Touch, pointer, and keyboard interaction.
- Image move, rotate, zoom, scale, flip, and skew controls.
- Multiple selections on one source image.
- Canvas export for the selected image area.
- Custom cropper templates.
- CSS-in-JS styles for the Web Components.
- On-demand imports for individual cropper elements.
How To Use Cropper.js
Install Cropper.js
Install the main package from npm.
npm install cropperjs
Basic Usage
The cropper requires an image and enough container height for the editing area. Import Cropper, then pass the image element or a selector to the constructor.
<div class="photo-cropper">
<img id="photo" src="photo.jpg" alt="Photo to crop">
</div>
<style>
.photo-cropper {
width: 100%;
max-width: 720px;
height: 420px;
}
.photo-cropper cropper-canvas {
height: 100%;
}
</style>import Cropper from 'cropperjs';
const cropper = new Cropper('#photo');CDN Setup
You can also directly load the browser build in your document.
<script src="https://unpkg.com/[email protected]/dist/cropper.js"></script> <script> const cropper = new Cropper('#photo'); </script>
Export The Cropped Image
The crop rectangle belongs to <cropper-selection>. Call $toCanvas() on that element when you need the selected pixels as a native <canvas>.
<button id="crop-button" type="button">Crop Image</button> <img id="crop-result" alt="Cropped result">
const selection = cropper.getCropperSelection();
const resultImage = document.querySelector('#crop-result');
document.querySelector('#crop-button').addEventListener('click', async () => {
if (!selection) return;
const canvas = await selection.$toCanvas();
canvas.toBlob((blob) => {
if (!blob) return;
resultImage.src = URL.createObjectURL(blob);
}, 'image/jpeg', 0.9);
});Set A Fixed Aspect Ratio
Set aspectRatio on the active selection for crops such as square avatars or 16:9 banners.
const selection = cropper.getCropperSelection();
if (selection) {
selection.aspectRatio = 16 / 9;
}Set The Crop Position And Size
The selection exposes x, y, width, and height. $change() updates those values in one call.
const selection = cropper.getCropperSelection();
if (selection) {
selection.$change(40, 30, 320, 180);
}Move, Rotate, Zoom, And Flip The Image
Get <cropper-image> when you need to change the source image under the crop box. Its methods control movement, rotation, zoom, scaling, flipping, skewing, and transform matrices.
const cropperImage = cropper.getCropperImage();
if (cropperImage) {
cropperImage.$move(20, 10);
cropperImage.$rotate('90deg');
cropperImage.$zoom(0.1);
cropperImage.$scale(-1, 1); // Flip horizontally.
}Reset The Image And Crop Selection
A reset action usually needs to restore both the image transform and the crop rectangle.
const cropperImage = cropper.getCropperImage(); const selection = cropper.getCropperSelection(); cropperImage?.$resetTransform(); selection?.$reset();
Build The Cropper UI With Web Components
Importing cropperjs registers the bundled Cropper elements automatically. Direct component markup keeps each canvas, image, selection, and handle available through the DOM.
import 'cropperjs';
<cropper-canvas background>
<cropper-image
src="photo.jpg"
alt="Photo to crop"
rotatable
scalable
skewable
translatable>
</cropper-image>
<cropper-shade hidden></cropper-shade>
<cropper-handle action="select" plain></cropper-handle>
<cropper-selection initial-coverage="0.5" movable resizable>
<cropper-grid role="grid" covered></cropper-grid>
<cropper-crosshair centered></cropper-crosshair>
<cropper-handle action="move" theme-color="rgba(255, 255, 255, 0.35)"></cropper-handle>
<cropper-handle action="n-resize"></cropper-handle>
<cropper-handle action="e-resize"></cropper-handle>
<cropper-handle action="s-resize"></cropper-handle>
<cropper-handle action="w-resize"></cropper-handle>
<cropper-handle action="ne-resize"></cropper-handle>
<cropper-handle action="nw-resize"></cropper-handle>
<cropper-handle action="se-resize"></cropper-handle>
<cropper-handle action="sw-resize"></cropper-handle>
</cropper-selection>
</cropper-canvas>Import Cropper Elements On Demand
Custom builds can install the element packages they actually use. Register each imported class with $define() before its custom element appears in the DOM.
npm install @cropper/element-canvas @cropper/element-image @cropper/element-selection
import CropperCanvas from '@cropper/element-canvas'; import CropperImage from '@cropper/element-image'; import CropperSelection from '@cropper/element-selection'; CropperCanvas.$define(); CropperImage.$define(); CropperSelection.$define();
Use A Custom Cropper Template
The template constructor option replaces the built-in component tree. Define the image, selection, handles, and other controls that the editor should render.
const cropper = new Cropper('#photo', {
template: `
<cropper-canvas background>
<cropper-image rotatable scalable translatable></cropper-image>
<cropper-shade hidden></cropper-shade>
<cropper-handle action="select" plain></cropper-handle>
<cropper-selection initial-coverage="0.6" movable resizable>
<cropper-grid role="grid" covered></cropper-grid>
<cropper-crosshair centered></cropper-crosshair>
<cropper-handle action="move"></cropper-handle>
<cropper-handle action="se-resize"></cropper-handle>
</cropper-selection>
</cropper-canvas>
`
});Core API Reference
After initialization, use the Cropper instance to access the canvas, image, and selection elements. Their properties and methods control the crop state.
Cropper Constructor Options
container(Element | string): Sets the Cropper container. The source element’s parent is used by default, withdocument.bodyas the fallback.template(string): Replaces the built-in Cropper template.
Cropper Instance Properties
element(HTMLImageElement | HTMLCanvasElement): The normalized image or canvas passed to the constructor.options(Object): The normalized constructor options.container(Element): The normalized Cropper container.
Cropper Instance Methods
// Return the <cropper-canvas> element. cropper.getCropperCanvas(); // Return the <cropper-image> element. cropper.getCropperImage(); // Return the first <cropper-selection> element. cropper.getCropperSelection(); // Return all <cropper-selection> elements. cropper.getCropperSelections(); // Destroy the Cropper instance. cropper.destroy();
CropperSelection Properties
x(number, default0): Horizontal coordinate of the selection.y(number, default0): Vertical coordinate of the selection.width(number, default0): Selection width.height(number, default0): Selection height.aspectRatio(number, defaultNaN): Fixed width-to-height ratio.initialAspectRatio(number, defaultNaN): Ratio used when the initial selection is created.initialCoverage(number, defaultNaN): Initial crop coverage from0to1.dynamic(boolean, defaultfalse): Keeps the selection geometry in sync with image changes.movable(boolean, defaultfalse): Turns on drag movement for the selection.resizable(boolean, defaultfalse): Turns on resize handles for the selection.zoomable(boolean, defaultfalse): Lets zoom actions change the selection size.multiple(boolean, defaultfalse): Turns on multiple selections.keyboard(boolean, defaultfalse): Adds keyboard controls to the active selection.outlined(boolean, defaultfalse): Displays an outline around the selection.precise(boolean, defaultfalse): Retains decimal values forx,y,width, andheight.
CropperSelection Keyboard Controls
Set keyboard to true when the active selection should respond to these keys.
DeleteorCommand + Backspace: Removes the active selection.ArrowLeft,ArrowRight,ArrowUp,ArrowDown: Moves the selection by 1 pixel.+: Zooms the selection in by 10%.-: Zooms the selection out by 10%.
CropperSelection Methods
// Center the selection inside its parent.
selection.$center();
// Move by an offset.
selection.$move(20, 10);
// Move to exact coordinates.
selection.$moveTo(80, 60);
// Resize from a side or corner.
selection.$resize('se-resize', 30, 20);
// Zoom the selection around its center.
selection.$zoom(0.1);
// Set position and size in one call.
selection.$change(40, 30, 320, 180);
// Restore the initial selection.
selection.$reset();
// Clear the selection.
selection.$clear();
// Refresh the rendered position and size.
selection.$render();
// Export the selected area to a canvas.
const croppedCanvas = await selection.$toCanvas();
// Export at a requested canvas size and adjust drawing before output.
const resizedCanvas = await selection.$toCanvas({
width: 640,
height: 360,
beforeDraw(context) {
context.imageSmoothingQuality = 'high';
}
});CropperImage Properties
initialFit(string, defaultcontain): Initial image size when centered in its parent. Accepted values arecover,fill,contain,scale-down, andnone.maxFit(string, default empty): Maximum image size relative to the parent.minFit(string, default empty): Minimum image size relative to the parent.rotatable(boolean, defaultfalse): Permits image rotation.scalable(boolean, defaultfalse): Permits image scaling.skewable(boolean, defaultfalse): Permits skew transforms.slottable(boolean, defaultfalse): Turns on the default slot.translatable(boolean, defaultfalse): Permits image translation.initialCenterSize(string, defaultcontain): Deprecated in 2.2.0. UseinitialFit.
CropperImage Methods
// Wait for the source image to load.
await cropperImage.$ready();
// Center the image and choose its centered size.
cropperImage.$center('contain');
// Move by an offset.
cropperImage.$move(20, 10);
// Move to exact coordinates.
cropperImage.$moveTo(80, 60);
// Rotate around the image center.
cropperImage.$rotate('45deg');
// Zoom in or out. The second and third arguments can set the zoom origin.
cropperImage.$zoom(0.1);
cropperImage.$zoom(-0.1);
// Scale or flip the image.
cropperImage.$scale(1.1);
cropperImage.$scale(-1, 1);
// Skew the image.
cropperImage.$skew('10deg', 0);
// Translate the image.
cropperImage.$translate(20, 10);
// Multiply the current transformation matrix.
cropperImage.$transform(1, 0, 0, 1, 20, 10);
// Replace the current transformation matrix.
cropperImage.$setTransform([1, 0, 0, 1, 20, 10]);
// Read the current transformation matrix.
const matrix = cropperImage.$getTransform();
// Restore the identity transformation matrix.
cropperImage.$resetTransform();CropperCanvas Properties
background(boolean, defaultfalse): Displays the grid background.disabled(boolean, defaultfalse): Blocks pointer interaction on the canvas.scaleStep(number, default0.1): Wheel zoom step.themeColor(string, default#39f): Primary color used by the canvas and its child elements.
CropperCanvas Methods
const cropperCanvas = cropper.getCropperCanvas();
// Change the active interaction action.
cropperCanvas?.$setAction('move');
// Render the cropper canvas to a native canvas element.
const fullCanvas = await cropperCanvas?.$toCanvas();Events
Canvas Action Events
<cropper-canvas> fires action, actionstart, actionmove, and actionend during pointer interaction. These events are cancelable. Call event.preventDefault() when an application needs to block the pending action.
const cropperCanvas = cropper.getCropperCanvas();
cropperCanvas?.addEventListener('action', (event) => {
console.log(event.detail.action);
});
cropperCanvas?.addEventListener('actionstart', (event) => {
console.log(event.detail.action);
});
cropperCanvas?.addEventListener('actionmove', (event) => {
console.log(event.detail.action);
});
cropperCanvas?.addEventListener('actionend', (event) => {
console.log(event.detail.action);
});Selection Change Event
<cropper-selection> fires change before its position or size changes. The event detail contains x, y, width, and height.
const selection = cropper.getCropperSelection();
selection?.addEventListener('change', (event) => {
const { x, y, width, height } = event.detail;
console.log(x, y, width, height);
});Image Transform And Change Events
<cropper-image> fires transform before its transformation matrix changes. The change event fires before its position or size changes.
const cropperImage = cropper.getCropperImage();
cropperImage?.addEventListener('transform', (event) => {
console.log(event.detail.matrix, event.detail.oldMatrix);
});
cropperImage?.addEventListener('change', (event) => {
console.log(event.detail.x, event.detail.y);
console.log(event.detail.width, event.detail.height);
});Cropper.js 1.x API Migration
In 2.x, image transforms, crop geometry, preview output, and pointer events moved to the Web Components that own those tasks.
aspectRatiomaps to<cropper-selection>.aspectRatio.getCroppedCanvas()maps to<cropper-selection>.$toCanvas().setAspectRatio()maps to<cropper-selection>.aspectRatio.move()maps to<cropper-image>.$move().moveTo()maps to<cropper-image>.$moveTo().zoom()maps to<cropper-image>.$scale().zoomTo()maps to<cropper-image>.$setTransform().rotate()maps to<cropper-image>.$rotate().scaleX()andscaleY()map to<cropper-image>.$scale().getData()maps to<cropper-image>.$getTransform()plus the selection’sx,y,width, andheight.cropstart,cropmove, andcropendmap toactionstart,actionmove, andactionendon<cropper-canvas>.previewmaps to<cropper-viewer>.
Alternatives And Related Resources
- Modern Image Crop Web Component – VanillaJCrop
- Vanilla JS Image Cropper with Image Zoom & Pan – PureJsCropper
- Lightweight & Fast Image Cropper In Vanilla JavaScript – Truecropper.js
- JavaScript & CSS Image Cropping Resources
FAQs
Q: Does Cropper.js require jQuery?
A: No. Cropper.js is a standalone JavaScript image cropper. The jQuery Cropper package wraps Cropper.js 1.x and depends on jQuery.
Q: Does Cropper.js 2.x require a CSS file?
A: No standalone stylesheet is required for the standard 2.x package. The Cropper elements use CSS-in-JS. Page CSS is still useful for container dimensions and project-specific styling.
Q: How do I get the cropped image in Cropper.js 2.x?
A: Get the active <cropper-selection> with cropper.getCropperSelection(), then await selection.$toCanvas(). Use the normal Canvas API to convert the result to a Blob or data URL.
Q: Why does getCroppedCanvas() not work in Cropper.js 2.x?
A: getCroppedCanvas() belongs to the 1.x API. Cropper.js 2.x uses $toCanvas() on <cropper-selection>.
Q: Why is the crop area too small?
A: Give the cropper container or <cropper-canvas> an explicit height that matches the editor layout. The built-in canvas minimum is 200px wide and 100px high.
Changelog
v2.2.0 (08/24/2026)
- Added
initialFit,maxFit, andminFitimage sizing controls. - Added the
changeevent to<cropper-image>. - Added
fill,scale-down, andnonemodes to$center(). - Added center-based scaling for images and selections.
- Added cancelable canvas action handling through
event.preventDefault(). - Fixed pointer, touch selection, grid, viewer, and custom-element issues.
v2.1.1 (04/06/2026)
- Fixed image centering when translation and scaling are disabled.
- Fixed shade rendering during resize.
- Fixed SVG preview sizing in Safari.
v2.1.0 (10/19/2025)
- Added the
destroy()method. - Fixed selection event handling in Shadow DOM.
- Improved image and shade rendering.
v2.0.1 (07/25/2025)
- Fixed package distribution files and image cross-origin attributes.
- Improved crop selection movement and custom-element container handling.
v2.0.0 (03/01/2025)
- Released the stable modular Web Components architecture for Cropper.js 2.x.
v1.6.1 (09/17/2023)
- Bug fixes.
v1.6.0 (08/26/2023)
- Added the
roundedoption to the 1.xgetCroppedCanvas()method.
v1.5.13 (11/20/2021)
- Added
backface-visibility: hiddento reduce ghost lines while moving the cropper image. - Removed the unused
cropper-hideclass from the cropper image. - Checked for a parent node before removing the cropper container.
v1.5.12 (06/12/2021)
- Fixed responsive behavior when only the cropper height changed.
v1.5.11 (02/17/2021)
- Fixed TypeScript declaration compatibility.
v1.5.10 (02/14/2021)
- Set XMLHttpRequest calls to asynchronous mode explicitly.
- Improved TypeScript declarations.
v1.5.6 (10/29/2019)
- Improved event type detection for iOS 13+.







