react-avatar-editor、react-cropper、react-image-crop はいずれも React 向けの画像トリミング(クロッピング)機能を提供するライブラリです。ユーザーが画像をドラッグ・スケールして任意の領域を切り抜ける UI を実装でき、SNSプロフィール設定や商品画像アップロードなどのシーンで活用されます。react-avatar-editor は Canvas ベースで即時出力が可能、react-cropper は成熟した Cropper.js の React ラッパー、react-image-crop は依存ゼロで React の状態管理と密結合した軽量設計という特徴を持ちます。
React アプリで画像のトリミングや編集機能を実装する際、react-avatar-editor、react-cropper、react-image-crop の3つの人気ライブラリがあります。これらはいずれもユーザーが画像を切り抜いたり、拡大縮小したりできる UI を提供しますが、アーキテクチャ、API 設計、出力形式、依存関係において重要な違いがあります。この記事では、プロフェッショナルなフロントエンド開発者が技術的判断を下すために必要な詳細を解説します。
react-avatar-editorユーザーがプロフィール画像などを円形または四角形にトリミングし、Canvas 上でプレビュー・エクスポートできるように設計されています。内部で <canvas> 要素を使用し、最終的に画像データ URL や Blob を生成します。主に「アバター選択」のような限定されたユースケース向けです。
react-cropperJavaScript ライブラリ Cropper.js の React ラッパーです。Cropper.js は広く使われている汎用的な画像トリミングライブラリで、豊富な設定オプションと操作メソッドを提供します。DOM ベースの操作(<img> 要素の変形)を採用しており、Canvas は使用しません。
react-image-crop軽量で依存関係ゼロの純粋な React コンポーネントです。CSS と React 状態管理のみで動作し、Canvas も外部ライブラリも使いません。トリミング領域(crop area)の座標とサイズを親コンポーネントにコールバックで通知し、実際の画像処理は別途行う必要があります。
各ライブラリは「トリミング UI」と「画像処理」の責務をどこまで担うかで大きく異なります。
react-avatar-editor: Canvas による直接出力このライブラリは <canvas> を使って即座にトリミング済み画像を生成できます。getImage() メソッドで HTMLCanvasElement を取得し、そこから PNG/JPEG データ URL や Blob を作成できます。
import AvatarEditor from 'react-avatar-editor';
function AvatarUploader() {
const editorRef = useRef(null);
const handleSave = () => {
if (editorRef.current) {
const canvas = editorRef.current.getImage();
const dataUrl = canvas.toDataURL('image/jpeg', 0.8);
// dataUrl をサーバーに送信 or 表示
}
};
return (
<>
<AvatarEditor
ref={editorRef}
image="/path/to/image.jpg"
width={250}
height={250}
border={50}
borderRadius={125} // 円形にする場合
scale={1.2}
/>
<button onClick={handleSave}>保存</button>
</>
);
}
react-cropper: Cropper.js の API 経由で出力Cropper.js は <img> 要素を操作し、getCroppedCanvas() メソッドでトリミング結果を Canvas として取得します。その後、toDataURL() や toBlob() で画像データを生成します。
import Cropper from 'react-cropper';
import 'cropperjs/dist/cropper.css';
function ImageCropper() {
const cropperRef = useRef(null);
const getCroppedImage = () => {
const imageElement = cropperRef?.current;
const cropper = imageElement?.cropper;
if (cropper) {
const croppedCanvas = cropper.getCroppedCanvas();
const dataUrl = croppedCanvas.toDataURL('image/jpeg', 0.8);
// 使用
}
};
return (
<>
<Cropper
ref={cropperRef}
src="/path/to/image.jpg"
aspectRatio={1}
guides={false}
cropBoxResizable={true}
/>
<button onClick={getCroppedImage}>トリミング</button>
</>
);
}
react-image-crop: 座標のみ提供、処理は別途このライブラリは UI と状態管理のみを担当し、実際の画像処理は開発者側で実装する必要があります。onCropComplete コールバックで { x, y, width, height } を受け取り、それを元に Canvas やサードパーティライブラリで画像を切り抜きます。
import React, { useState } from 'react';
import ReactCrop from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';
function CropDemo() {
const [crop, setCrop] = useState({ aspect: 1 });
const [completedCrop, setCompletedCrop] = useState(null);
const handleCropComplete = (c) => {
setCompletedCrop(c);
// 実際の画像処理は別の関数で行う(例: getCroppedImg)
};
return (
<ReactCrop
src="/path/to/image.jpg"
crop={crop}
onChange={setCrop}
onComplete={handleCropComplete}
/>
);
}
💡 注意:
react-image-crop自体は画像を生成しません。completedCropの値を使って、別途canvasで画像を描画する必要があります。
react-avatar-editorborderRadius)に特化scale)、回転(rotate)に対応react-cropperaspectRatio、viewMode、dragMode など多数のオプションreact-image-cropcrop, onChange, onComplete)ruleOfThirds(三分割法ガイド)などの軽量機能ありreact-avatar-editor: 依存は少ないが、Canvas 操作のためブラウザ環境に依存react-cropper: Cropper.js(約 40KB minified)に依存。CSS ファイルのインポートも必須react-image-crop: 依存ゼロ。React と CSS のみ。軽量で SSR(サーバーサイドレンダリング)にも対応しやすいreact-avatar-editor: 内部状態を持ち、ref 経由での操作が主。React の宣言的パターンとはやや距離があるreact-cropper: Cropper.js のインスタンスを ref で取得し、命令的に操作する必要があるreact-image-crop: 完全に React の状態(useState)と連動。crop オブジェクトを親で管理し、再レンダリングも自然執筆時点(2024年)で、いずれのパッケージも npm または GitHub で非推奨(deprecated)と明記されていません。ただし、react-avatar-editor は長期間大きな更新がなく、保守状況には注意が必要です。一方、react-image-crop と react-cropper は定期的に更新されています。
→ react-avatar-editor
→ react-cropper
→ react-image-crop
| 特徴 | react-avatar-editor | react-cropper | react-image-crop |
|---|---|---|---|
| 出力方法 | Canvas 直接出力 | Cropper.js → Canvas | 座標のみ提供 |
| 依存関係 | 少ない | Cropper.js + CSS | なし |
| React との統合 | ref 中心 | ref + 命令型 | 宣言的(state 駆動) |
| カスタマイズ性 | 限定的 | 非常に高い | 中程度(UI は CSS で) |
| SSR 対応 | ❌(Canvas 依存) | ⚠️(クライアント限定) | ✅(条件付き) |
| 最適な用途 | アバター選択 | 汎用画像編集ツール | 軽量トリミング UI |
react-avatar-editor(ただし保守状況要確認)react-cropperreact-image-cropどのライブラリも一長一短があります。プロジェクトの規模、チームのスキル、長期保守性を考慮して選んでください。特に、画像処理をサーバー側で行う場合や、Canvas を避けたい場合は react-image-crop が安全牌です。逆に、高機能な UI が求められるなら react-cropper の成熟度が頼りになります。
react-image-crop は、依存関係ゼロで軽量、かつ React の状態管理と自然に統合できる点が最大の強みです。トリミング座標をコールバックで受け取り、画像処理ロジックを自分で制御したい場合や、バンドルサイズを最小限に抑えたいプロジェクトに最適です。ただし、実際の画像生成は別途実装が必要で、初心者には少しハードルが高いかもしれません。
react-avatar-editor は、プロフィール画像などの円形トリミングをすぐに実装したい場合に適しています。Canvas を使って直接画像データを生成できるため、追加の画像処理コードが不要です。ただし、長期間大きな更新がなく、高度なカスタマイズや最新の React パターン(例:Server Components)との互換性には注意が必要です。単純なアバター選択機能で十分なら有力な選択肢です。
react-cropper は、Cropper.js の豊富な機能(ガイド線、回転、グリッド、レスポンシブ対応など)をそのまま React で使いたい場合に最適です。複雑な画像編集 UI や高カスタマイズ性が求められるプロジェクトに向いています。ただし、Cropper.js 本体と CSS ファイルに依存するため、バンドルサイズが増加し、React の宣言的パラダイムからはやや外れた命令的な操作が必要になります。
An image cropping tool for React with no dependencies.

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.
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.
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'
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.
<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.
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.
This isn't part of the library but there is an example over here CodeSandbox Demo.
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.
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.

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:
<ReactCrop crop={crop} aspect={16 / 9}>
<img src={src} onLoad={onImageLoad} />
</ReactCrop>
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} ... />.
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.