Cropper.js - JavaScript Image Cropper
Cropper.js is a powerful, pure JavaScript library for image cropping that provides extensive functionalities including moving, zooming, rotating, and scaling images directly within web browsers. The current stable version is 2.1.1, with the project demonstrating active maintenance through consistent patch and minor releases, indicating ongoing development and bug fixes. A key differentiator is its standalone nature, operating without external dependencies like jQuery, making it lightweight and suitable for modern JavaScript ecosystems. It offers a highly configurable and extensible API, allowing developers to tailor the cropping experience precisely. The library ships with comprehensive TypeScript declaration files, ensuring excellent developer experience in TypeScript projects, and supports both UMD and ESM module formats for broad compatibility across different environments.
Common errors
-
Uncaught TypeError: Cannot read properties of undefined (reading 'appendChild')
cause Cropper.js CSS file is not loaded, leading to rendering issues or JavaScript errors when the library tries to manipulate non-existent or incorrectly styled elements.fixAdd `import 'cropperjs/dist/cropper.css';` to your main JavaScript/TypeScript file or ensure the CSS is included in your HTML. -
Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
cause Attempting to export a canvas as an image (e.g., `toDataURL`, `toBlob`) when the image source is from a different origin and CORS headers are not correctly configured.fixAdd the `crossorigin="anonymous"` attribute to your `<img>` tag. Verify the image server is configured to send `Access-Control-Allow-Origin` headers that permit requests from your domain. -
Cropper is not a constructor
cause Using `require('cropperjs')` directly in a CommonJS environment without accessing the default export.fixFor CommonJS, use `const Cropper = require('cropperjs').default;`. For modern JavaScript modules, stick to `import Cropper from 'cropperjs';` and ensure your bundler (e.g., Webpack, Rollup) or TypeScript configuration (`esModuleInterop: true`) handles default interop correctly. -
Image glitches or crop box appears unstable during drag/resize.
cause This can stem from conflicting global CSS styles (e.g., `box-sizing`), or complex DOM structures like Shadow DOM where event target calculation can be tricky.fixInspect your CSS for conflicting rules, particularly `box-sizing` on elements within or around the cropper. Ensure no other scripts are interfering with mouse events. Check if upgrading to a newer Cropper.js version (e.g., v2.1.0 addressed shadow DOM event target issues) resolves the problem.
Warnings
- breaking In v2.0.0-rc, the default values for `rotatable`, `scalable`, `skewable`, and `translatable` properties on `CropperImage` were changed from `true` to `false`. Features that previously worked out-of-the-box now require explicit enabling through options.
- breaking In v2.0.0-rc.0, the `linked` property of `CropperSelection` was renamed to `dynamic`. Any code referencing the `linked` property will break.
- gotcha Cropper.js relies heavily on its default CSS for correct rendering and functionality. If the UI appears broken or non-functional, it's often due to missing or improperly loaded styles.
- gotcha When loading images from a different origin (domain, protocol, or port), using `getCroppedCanvas()` will result in a 'Tainted canvases may not be exported' error due to browser security restrictions (CORS).
Install
-
npm install cropperjs -
yarn add cropperjs -
pnpm add cropperjs
Imports
- Cropper
const Cropper = require('cropperjs');import Cropper from 'cropperjs';
- CropperOptions
import type { CropperOptions } from 'cropperjs'; - CSS
import 'cropperjs/dist/cropper.css';
Quickstart
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
document.addEventListener('DOMContentLoaded', () => {
const container = document.createElement('div');
container.style.width = '800px';
container.style.height = '600px';
container.style.margin = '20px auto';
container.style.border = '1px solid #ccc';
container.style.display = 'flex';
container.style.justifyContent = 'center';
container.style.alignItems = 'center';
document.body.appendChild(container);
const image = document.createElement('img');
image.id = 'image-to-crop';
image.src = 'https://picsum.photos/800/600'; // Example image source
image.alt = 'Image for cropping';
image.style.maxWidth = '100%';
image.style.maxHeight = '100%';
container.appendChild(image);
// Wait for the image to load before initializing Cropper
image.onload = () => {
const cropper = new Cropper(image, {
aspectRatio: 16 / 9,
viewMode: 1, // 0: no restrictions, 1: restrict to container, 2: restrict to canvas, 3: restrict to image
background: false, // Hide the grid background
crop(event) {
console.log('Crop data:', event.detail);
},
ready() {
console.log('Cropper is ready!');
}
});
// Example: Destroy cropper after 10 seconds
// setTimeout(() => {
// cropper.destroy();
// console.log('Cropper destroyed.');
// }, 10000);
};
});