react-image-crop vs react-avatar-editor vs react-cropper
React Image Cropping Libraries
react-image-cropreact-avatar-editorreact-cropperSimilar Packages:

React Image Cropping Libraries

react-avatar-editor, react-cropper, and react-image-crop are React libraries that enable image cropping functionality in web applications. They allow users to select a region of an image, adjust boundaries, enforce aspect ratios, and export the cropped result. Each takes a different technical approach: react-avatar-editor uses HTML canvas, react-cropper wraps the vanilla Cropper.js library, and react-image-crop implements cropping purely with React and CSS. These differences affect performance, customization, maintainability, and ease of integration.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
react-image-crop1,217,5434,084112 kB72a year agoISC
react-avatar-editor400,482-189 kB-3 months agoMIT
react-cropper345,3572,07820.5 kB153 years agoMIT

React Image Cropping Libraries Compared: react-avatar-editor vs react-cropper vs react-image-crop

When you need to let users crop images in a React app — for profile pictures, content uploads, or design tools — you have several solid options. The three most common libraries are react-avatar-editor, react-cropper, and react-image-crop. They all solve the same basic problem but with very different approaches, APIs, and trade-offs. Let’s break them down from an engineering perspective.

🖼️ Core Philosophy: Canvas vs DOM vs Pure React

Each library uses a fundamentally different rendering strategy, which affects performance, customization, and integration.

react-avatar-editor uses the <canvas> element under the hood. It draws the image onto a canvas and manipulates it directly using 2D context APIs. This gives you pixel-level control and makes exporting easy, but limits styling flexibility.

import AvatarEditor from 'react-avatar-editor';

function Editor() {
  return (
    <AvatarEditor
      image="/photo.jpg"
      width={250}
      height={250}
      border={50}
      color={[255, 255, 255, 0.6]} // RGBA
      scale={1.2}
      rotate={0}
    />
  );
}

react-cropper wraps the popular Cropper.js library (a vanilla JavaScript tool) in a React component. It manipulates the DOM directly using absolute-positioned overlays on top of an <img> tag. This means it’s not "React-native" — it uses refs and side effects heavily.

import Cropper from 'react-cropper';
import 'cropperjs/dist/cropper.css';

function Editor() {
  const cropperRef = useRef(null);

  const getCropData = () => {
    const imageElement = cropperRef?.current;
    const cropper = imageElement?.cropper;
    console.log(cropper.getCroppedCanvas().toDataURL());
  };

  return (
    <>
      <Cropper
        src="/photo.jpg"
        style={{ height: 400, width: '100%' }}
        initialAspectRatio={1}
        guides={false}
        ref={cropperRef}
      />
      <button onClick={getCropData}>Crop</button>
    </>
  );
}

react-image-crop is built entirely with React and CSS — no canvas, no external DOM manipulation. It uses absolutely positioned <div> elements to draw the crop area over an <img>. This makes it lightweight and easier to theme with standard CSS.

import React, { useState } from 'react';
import ReactCrop from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';

function Editor() {
  const [crop, setCrop] = useState({ aspect: 1 });

  return (
    <ReactCrop
      src="/photo.jpg"
      crop={crop}
      onChange={c => setCrop(c)}
    />
  );
}

📐 Aspect Ratio & Constraint Handling

How each library enforces aspect ratios and minimum/maximum sizes varies significantly.

react-avatar-editor only supports fixed width and height. You define exact pixel dimensions, and the crop area is always that size. There’s no dynamic resizing by the user — they can only move and zoom the image within the fixed frame.

// Fixed 300x300 crop area — user cannot change shape
<AvatarEditor width={300} height={300} />

react-cropper offers full control: freeform, fixed aspect ratio, min/max dimensions, and even grid snapping. You configure this via props like aspectRatio, minWidth, viewMode, etc.

<Cropper
  aspectRatio={16 / 9}
  minWidth={200}
  minHeight={100}
  viewMode={1} // restrict crop box to container
/>

react-image-crop supports both freeform and fixed aspect ratios, and lets users resize the crop box unless you lock it. You control behavior via the crop state object.

// Allow user to resize, but keep 1:1 aspect
const [crop, setCrop] = useState({ unit: '%', width: 50, aspect: 1 });

<ReactCrop crop={crop} onChange={setCrop} />

🖨️ Exporting Cropped Images

Getting the final cropped image out is critical — and the methods differ.

react-avatar-editor provides a direct method to get a canvas reference, then export as data URL or blob:

const editorRef = useRef(null);

const handleSave = () => {
  if (editorRef.current) {
    const canvas = editorRef.current.getImage();
    const dataUrl = canvas.toDataURL();
    // Or: canvas.toBlob(blob => upload(blob));
  }
};

<AvatarEditor ref={editorRef} />

react-cropper requires accessing the underlying Cropper.js instance through a ref:

const cropperRef = useRef(null);

const handleSave = () => {
  const cropper = cropperRef.current?.cropper;
  if (cropper) {
    const canvas = cropper.getCroppedCanvas();
    const dataUrl = canvas.toDataURL('image/jpeg');
  }
};

<Cropper ref={cropperRef} />

react-image-crop doesn’t include export logic — you must implement cropping yourself using a canvas:

import { getCroppedImg } from './utils'; // You write this

const [completedCrop, setCompletedCrop] = useState(null);

useEffect(() => {
  if (completedCrop?.width && completedCrop?.height) {
    getCroppedImg(imageRef.current, completedCrop)
      .then(canvas => canvas.toDataURL());
  }
}, [completedCrop]);

<ReactCrop onComplete={c => setCompletedCrop(c)} />

The library provides a helper example in its docs, but you own the implementation.

🎨 Styling and Customization

react-avatar-editor is hard to style beyond background color and border size because it’s canvas-based. You can’t use CSS to change handles or overlay appearance.

react-cropper inherits Cropper.js’s extensive but non-React styling system. You override CSS classes like .cropper-view-box or .cropper-face. This works but feels disconnected from your component tree.

react-image-crop exposes CSS classes you can target (e.g., .ReactCrop__crop-selection), and since it’s pure React + CSS, you can easily wrap it in styled-components or pass custom class names.

⚙️ Maintenance Status (Critical!)

As of 2024:

  • react-avatar-editor is deprecated. Its npm page states: "This package has been deprecated. Please use @davidtheclark/react-avatar-editor instead." However, the suggested fork hasn’t gained traction and lacks recent updates. Avoid in new projects.
  • react-cropper is actively maintained and tracks updates to Cropper.js.
  • react-image-crop is actively maintained, with regular releases and TypeScript support.

🧪 Real-World Use Case Guidance

Use react-cropper if:

  • You need advanced features like rotation, flipping, zoom-to-pointer, or grid guides.
  • Your designers require pixel-perfect control over the UI (via CSS overrides).
  • You’re okay with a larger bundle and non-React internals.

Use react-image-crop if:

  • You want a lightweight, React-first solution.
  • Your app uses modern React patterns (hooks, functional components).
  • You prefer to own the export logic for maximum flexibility (e.g., Web Workers for large images).
  • You need TypeScript support out of the box.

Avoid react-avatar-editor if:

  • You’re starting a new project — it’s deprecated.
  • You need user-resizable crop areas — it only supports fixed frames.
  • You care about long-term maintenance.

📊 Summary Table

Featurereact-avatar-editorreact-cropperreact-image-crop
RenderingCanvasDOM (Cropper.js wrapper)Pure React + CSS
User Resizing❌ Fixed frame only✅ Full control✅ Configurable
Aspect Ratio Lock❌ (Fixed dims only)✅ Yes✅ Yes
Export Built-in✅ Direct canvas access✅ Via Cropper.js API❌ Manual implementation
Styling Flexibility❌ Very limited✅ Via global CSS✅ Component-scoped CSS
Maintenance Status⚠️ Deprecated✅ Active✅ Active
Bundle ImpactMediumLarge (includes Cropper.js)Small

💡 Final Recommendation

For new projects, choose between react-cropper and react-image-crop based on your needs:

  • Need batteries-included, enterprise-grade cropping with minimal custom code? → react-cropper.
  • Prefer lightweight, composable, React-native behavior and don’t mind writing a few lines for export? → react-image-crop.

And do not use react-avatar-editor in any new codebase — its deprecation makes it a technical liability.

How to Choose: react-image-crop vs react-avatar-editor vs react-cropper

  • react-image-crop:

    Choose react-image-crop for a lightweight, React-native solution that integrates cleanly with modern hooks-based architecture and TypeScript. It’s best when you want full control over the export pipeline (e.g., offloading cropping to a Web Worker) and prefer styling via standard CSS or CSS-in-JS. Accept that you’ll need to implement the canvas-based image extraction logic yourself, though the library provides clear examples.

  • react-avatar-editor:

    Do not use react-avatar-editor in new projects — it is officially deprecated as noted on its npm page. While it offers simple canvas-based cropping with fixed dimensions, its lack of active maintenance and inability to support user-resizable crop areas make it unsuitable for modern applications. If you encounter it in legacy code, plan a migration to an alternative.

  • react-cropper:

    Choose react-cropper when you need a mature, feature-rich cropping experience with advanced capabilities like rotation, zoom-to-pointer, grid guides, and precise aspect ratio controls. It’s ideal if your team is comfortable working with a DOM-manipulating wrapper around a vanilla JS library and can manage the larger bundle size. Ensure you’re prepared to customize appearance via global CSS overrides rather than React props.

README for react-image-crop

React Image Crop

An image cropping tool for React with no dependencies.

React Image Crop on NPM

CodeSandbox Demo

ReactCrop GIF

Table of Contents

  1. Features
  2. Installation
  3. Usage
  4. Example
  5. CDN
  6. Props
  7. FAQ
    1. How can I generate a crop preview in the browser?
    2. How to correct image EXIF orientation/rotation?
    3. How to filter, rotate and annotate?
    4. How can I center the crop?
  8. Contributing / Developing

Features

  • Responsive (you can use pixels or percentages).
  • Touch enabled.
  • Free-form or fixed aspect crops.
  • Fully keyboard accessible (a11y).
  • No dependencies/small footprint (<5KB gzip).
  • Min/max crop size.
  • Crop anything, not just images.

If React Crop doesn't cover your requirements then take a look at Pintura (our sponsor). It features cropping, rotating, filtering, annotation, and lots more.

Learn more about Pintura here

Installation

npm i react-image-crop --save
yarn add react-image-crop
pnpm add react-image-crop

This library works with all modern browsers. It does not work with IE.

Usage

Include the main js module:

import ReactCrop from 'react-image-crop'

Include either dist/ReactCrop.css or ReactCrop.scss.

import 'react-image-crop/dist/ReactCrop.css'
// or scss:
import 'react-image-crop/src/ReactCrop.scss'

Example

import ReactCrop, { type Crop } from 'react-image-crop'

function CropDemo({ src }) {
  const [crop, setCrop] = useState<Crop>()
  return (
    <ReactCrop crop={crop} onChange={c => setCrop(c)}>
      <img src={src} />
    </ReactCrop>
  )
}

See the sandbox demo for a more complete example.

CDN

<link href="https://unpkg.com/react-image-crop/dist/ReactCrop.css" rel="stylesheet" />
<script src="https://unpkg.com/react-image-crop/dist/index.umd.cjs"></script>

Note when importing the script globally using a <script> tag access the component with ReactCrop.Component.

Props

onChange: (crop: PixelCrop, percentCrop: PercentCrop) => void

A callback which happens for every change of the crop (i.e. many times as you are dragging/resizing). Passes the current crop state object.

Note you must implement this callback and update your crop state, otherwise nothing will change!

<ReactCrop crop={crop} onChange={(crop, percentCrop) => setCrop(crop)} />

crop and percentCrop are interchangeable. crop uses pixels and percentCrop uses percentages to position and size itself. Percent crops are resistant to image/media resizing.

crop?: Crop

Starting with no crop:

const [crop, setCrop] = useState<Crop>()

<ReactCrop crop={crop} onChange={c => setCrop(c)}>
  <img src={src} />
</ReactCrop>

Starting with a preselected crop:

const [crop, setCrop] = useState<Crop>({
  unit: '%', // Can be 'px' or '%'
  x: 25,
  y: 25,
  width: 50,
  height: 50
})

<ReactCrop crop={crop} onChange={c => setCrop(c)}>
  <img src={src} />
</ReactCrop>

⚠️ You must ensure the crop is in bounds and correct to the aspect ratio if manually setting. Aspect ratios can be tricky when using %. You can make use of centerCrop and makeAspectCrop helpers. See How can I center the crop? or the CodeSanbox Demo for examples.

aspect?: number

The aspect ratio of the crop, e.g. 1 for a square or 16 / 9 for landscape. Omit/pass undefined for a free-form crop.

minWidth?: number

A minimum crop width, in pixels.

minHeight?: number

A minimum crop height, in pixels.

maxWidth?: number

A maximum crop width, in pixels.

maxHeight?: number

A maximum crop height, in pixels.

keepSelection?: boolean

If true is passed then selection can't be disabled if the user clicks outside the selection area.

disabled?: boolean

If true then the user cannot resize or draw a new crop. A class of ReactCrop--disabled is also added to the container for user styling.

locked?: boolean

If true then the user cannot create or resize a crop, but can still drag the existing crop around. A class of ReactCrop--locked is also added to the container for user styling.

className?: string

A string of classes to add to the main ReactCrop element.

style?: React.CSSProperties

Inline styles object to be passed to the image wrapper element.

onComplete?: (crop: PixelCrop, percentCrop: PercentCrop) => void

A callback which happens after a resize, drag, or nudge. Passes the current crop state object.

percentCrop is the crop as a percentage. A typical use case for it would be to save it so that the user's crop can be restored regardless of the size of the image (for example saving it on desktop, and then using it on a mobile where the image is smaller).

onDragStart?: (e: PointerEvent) => void

A callback which happens when a user starts dragging or resizing. It is convenient to manipulate elements outside this component.

onDragEnd?: (e: PointerEvent) => void

A callback which happens when a user releases the cursor or touch after dragging or resizing.

renderSelectionAddon?: (state: ReactCropState) => React.ReactNode

Render a custom element inside the crop selection.

ruleOfThirds?: boolean

Show rule of thirds lines in the cropped area. Defaults to false.

circularCrop?: boolean

Show the crop area as a circle. If your aspect is not 1 (a square) then the circle will be warped into an oval shape. Defaults to false.

FAQ

How can I generate a crop preview in the browser?

This isn't part of the library but there is an example over here CodeSandbox Demo.

How to correct image EXIF orientation/rotation?

You might find that some images are rotated incorrectly. Unfortunately this is a browser wide issue not related to this library. You need to fix your image before passing it in.

You can use the following library to load images, which will correct the rotation for you: https://github.com/blueimp/JavaScript-Load-Image/

You can read an issue on this subject here: https://github.com/dominictobias/react-image-crop/issues/181

If you're looking for a complete out of the box image editor which already handles EXIF rotation then consider using Pintura.

How to filter, rotate and annotate?

This library is deliberately lightweight and minimal for you to build features on top of. If you wish to perform more advanced image editing out of the box then consider using Pintura.

Pintura Demo

How can I center the crop?

The easiest way is to use the percentage unit:

crop: {
  unit: '%',
  width: 50,
  height: 50,
  x: 25,
  y: 25
}

Centering an aspect ratio crop is trickier especially when dealing with %. However two helper functions are provided:

  1. Listen to the load event of your media to get its size:
<ReactCrop crop={crop} aspect={16 / 9}>
  <img src={src} onLoad={onImageLoad} />
</ReactCrop>
  1. Use makeAspectCrop to create your desired aspect and then centerCrop to center it:
function onImageLoad(e) {
  const { naturalWidth: width, naturalHeight: height } = e.currentTarget

  const crop = centerCrop(
    makeAspectCrop(
      {
        // You don't need to pass a complete crop into
        // makeAspectCrop or centerCrop.
        unit: '%',
        width: 90,
      },
      16 / 9,
      width,
      height
    ),
    width,
    height
  )

  setCrop(crop)
}

Also remember to set your crop using the percentCrop on changes:

const onCropChange = (crop, percentCrop) => setCrop(percentCrop)

And your aspect prop should be set to the same value: <ReactCrop aspect={16 / 9} ... />.

Contributing / Developing

To develop run pnpm install && pnpm dev and open the localhost server in your browser. Update code and it will reload. When you're ready, open a pull request.