react-easy-crop vs react-image-crop vs react-advanced-cropper: choosing a Next.js image cropper in 2026
Three React image croppers whose received wisdom is three months out of date. Read from the npm registry, the published tarballs and the GitHub API on 1 October 2026: the library everyone calls selection-only now writes the canvas code for you, the most downloaded one still ships zero canvas code, and the package npm reports as smallest is actually the heaviest.
On this page
Quick answer (October 2026). The received wisdom about these three is about three months out of date. Measured live from the npm registry, the published tarballs and the GitHub API on 1 October 2026: react-image-crop, the library every roundup describes as selection-only, began shipping its own canvas output helpers in v11.1.0 on 21 June 2026 and now hands you a finished image. react-easy-crop, the most downloaded of the three at 3,946,859 weekly installs, still ships zero canvas code, and so does its unreleased v7 canary. react-advanced-cropper, the least downloaded by a factor of nineteen, is the only one whose design has always been to give you a canvas.
So the question is not which is easiest. It is what you want back from the component: coordinates, a canvas, or a ready-made object URL.
The axis that actually separates them
Every cropper has to answer one question: when the user stops dragging, what does your code receive?
Scroll to see more
| react-easy-crop 6.2.3 | react-image-crop 11.1.2 | react-advanced-cropper 0.20.1 | |
|---|---|---|---|
| What you get back | Crop rectangle only | Crop rectangle, plus canvas and object-URL helpers | A canvas, via getCanvas() |
canvas in shipped code | 0 occurrences | 2 runtime, 3 in types | 96 runtime, 15 in types |
| Public exported names | component and props type | 21 | 91 |
| Type surface shipped | 7,192 B over 2 files | 8,478 B over 2 files | 43,240 B over 52 files |
| Weekly installs | 3,946,859 | 3,045,055 | 207,435 |
| Runtime dependencies | normalize-wheel | none | advanced-cropper, classnames, tslib |
Weekly figures are npm's own count for 23 to 29 September 2026. The occurrence counts are a case-insensitive scan of every .d.ts, .js and .mjs file in each published tarball, not a reading of the documentation.
That first row is the whole decision, and it is the row the popular roundups get wrong.
The claim that stopped being true in June 2026
If you search for a React cropper you will be told, repeatedly, that react-image-crop is a minimal selection overlay and that producing the actual cropped image is your job. That was true for years. It is not true now.
Version 11.1.0, published 21 June 2026, added two exported functions. From the shipped type definitions:
Scroll to see more
| Exported function | Parameters | Resolves to |
|---|---|---|
cropToCanvas | image, canvas, crop, optional scale, optional rotate | nothing; it draws into the canvas you pass |
cropToImg | image, crop, optional scale, optional rotate | a string, an object URL for the cropped image |
Both are declared in the shipped .d.ts, typed against HTMLImageElement, HTMLCanvasElement and the library's own PixelCrop, and both return promises.
cropToImg creates a canvas for you, draws the crop with the scale and rotation applied, converts it with toBlob, and returns an object URL. It also revokes the previous object URL it handed out, which is the leak most hand-rolled versions of this code forget.
Scanning the tarballs version by version dates the change precisely:
Scroll to see more
| Version | Published | cropToCanvas | cropToImg |
|---|---|---|---|
| 11.0.7 | 2024-09-09 | absent | absent |
| 11.0.10 | 2025-04-14 | absent | absent |
| 11.1.0 | 2026-06-21 | present | present |
| 11.1.2 | 2026-06-21 | present | present |
Three months is not long enough for the advice layer to catch up, which is why the listicles still describe the old behaviour.
The mirror image is react-easy-crop. Its documentation is famous for a getCroppedImg helper, and that helper is demo code in the docs, not an export. Scanning its tarball for canvas, drawImage, toBlob, toDataURL and OffscreenCanvas returns zero hits in both the runtime and the types. The same scan against the newest v7 canary, published 5 September 2026, also returns zero. Coordinates-only is a deliberate and continuing design choice there, not a gap waiting to be filled.
Weight, measured from the tarballs
Bundle size is the question people actually ask about croppers, and npm's headline number answers it badly.
Scroll to see more
| Package | npm unpacked | Real ESM entry | Gzipped | Stylesheet |
|---|---|---|---|---|
| react-image-crop | 115,367 B | 19,684 B | 5,028 B | 4,791 B |
| react-easy-crop | 281,101 B | 38,213 B | 8,148 B | 1,578 B |
| react-advanced-cropper | 1,125,449 B | 81,758 B | 14,161 B | 1,191 to 2,622 B per theme |
| react-cropper | 20,486 B | 2,944 B, plus Cropper.js | 1,323 B, plus 23,294 B | 4,978 B |
Read the first column on its own and react-cropper is the lightest option by a factor of five and react-advanced-cropper is a monster. Both readings are wrong.
react-advanced-cropper's 1.1 MB is 72 files of themes, source maps and multiple build targets. The thing your bundler actually pulls is 81,758 B, and 14,161 B gzipped.
react-cropper is the inverse and the more serious trap. It is a 2,944 B wrapper that declares cropperjs version 1.5.13 or compatible as a runtime dependency, so installing it pulls in Cropper.js 1.6.3, whose ESM entry is 108,396 B and 23,294 B gzipped. The honest total is roughly 111 KB raw and 24.6 KB gzipped, which makes the apparently smallest package the heaviest of the four.
These are upper bounds. All four ship ESM and mark themselves tree-shakeable or side-effect-scoped, so a real application will drop some of this. The ranking between them is what matters, and the ranking survives.
Maintenance, read properly
GitHub's pushed_at field is a poor maintenance signal because it counts a push to any branch, including an unattended bot.
Scroll to see more
| Stars | pushed_at | Last commit on default branch | Open issues | Open PRs | |
|---|---|---|---|---|---|
| react-image-crop | 4,105 | 2026-06-21 | 2026-06-21 | 68 | 5 |
| react-easy-crop | 2,779 | 2026-09-10 | 2026-07-24 | 5 | 1 |
| react-advanced-cropper | 886 | 2026-07-25 | 2026-07-25 | 14 | 1 |
| react-cropper | 2,076 | 2023-09-11 | 2023-09-11 | 3 | 12 |
Two notes on reading that table.
First, react-easy-crop's pushed_at is nine weeks newer than its default branch, and the difference is not neglect. The 10 September push was a Dependabot bump of vitest. The real work is on a branch called feat/hooks-react-compiler-v7, last touched 5 September 2026, and it is being published to npm under the canary tag. So the project is not drifting, it is being rewritten one branch over. A naive reading of either field alone gets this wrong in opposite directions.
Second, GitHub's open_issues_count includes pull requests. react-image-crop's raw count is 73; separating them gives 68 issues and 5 PRs. react-cropper's raw count of 15 is 3 issues and 12 pull requests, and eleven of its fourteen branches are Dependabot or Renovate. That is the signature of a repository nobody is steering.
If you are on React 18 and planning ahead, note that the v7 canary of react-easy-crop declares a peer dependency of React 19.2 or newer, where the released v6 line accepts React 16.4 and above. The released versions of all three are permissive: react-image-crop wants React 16.13.1 or newer, react-advanced-cropper 16.8.0 or newer. None of them blocks React 19 today.
Licences, which are not all MIT
This is the kind of detail a dependency policy review catches late.
- react-easy-crop ships a 1,073 B
LICENSE, plain MIT. - react-image-crop is ISC, not MIT, in a 784 B
LICENSE.md. ISC is permissive and functionally equivalent for most purposes, but it is a different identifier and some automated policy checks are configured with an explicit allowlist. - react-advanced-cropper is the interesting one. npm's one-word field says
MIT. GitHub's licence detector saysNOASSERTION. The actual 1,257 B file opens with a scope line before the MIT text: the source code is MIT, the documentation content belongs to the author, and the photos belong to their respective owners.
The MIT body underneath is unmodified, so this does not restrict shipping the library. It matters only if you copy the documentation prose or the demo photographs into your own material. The reason the two registries disagree is exactly that preamble, and a one-word metadata field cannot express a condition. Worth knowing, not worth worrying about.
One further note if you go down the react-advanced-cropper path: its core package, advanced-cropper 0.17.1, ships no licence file at all in its tarball. Its only grant is the license field in package.json.
The two others you will be recommended
The roundups that rank these libraries almost always include two more, and both need a caveat.
react-cropper is a React wrapper around Cropper.js, at 517,476 weekly installs. Its last release was April 2023 and its last commit September 2023. It pins Cropper.js to the version 1 line while Cropper.js shipped 2.2.0 in August 2026, a rewrite built on custom elements that the wrapper's component model does not fit.
The tempting conclusion is that this leaves you stranded, and that is not what the registry shows. Cropper.js published 1.6.3 on 23 August 2026, the same day as 2.2.0. The v1 line is still receiving releases. So react-cropper is a dormant wrapper over a maintained dependency, which is a milder problem than an abandoned stack, though it does mean the v2 rewrite is not reachable through it.
react-avatar-editor is 865,884 weekly installs and published v16.0.0 on 1 October 2026, so it is the most actively released package in this space. It is also a different tool: a fixed circular or square avatar editor rather than a general cropper. If you only need profile pictures it is a reasonable answer, and it is not a competitor to the three above.
How to choose
- You want the component to produce the finished image and you want the smallest bundle: react-image-crop. Since 11.1.0 it does the canvas work, it is the lightest at 5,028 B gzipped, it has no runtime dependencies, and ISC is fine for almost every policy. The cost is 68 open issues and the largest backlog of the three.
- You want the familiar pinch, zoom and rotate interaction and you are happy to own the output step: react-easy-crop. It is the most installed, it has the cleanest issue tracker by a wide margin, and you will copy about twenty lines of canvas code out of its documentation. Check the v7 branch before starting anything long-lived.
- You want to build a cropper that does not look like a cropper, with custom stencils and your own interaction rules: react-advanced-cropper. The 91 exported names and 52 type files are the point, not bloat, and
getCanvas()means you never write the output step. You are accepting the smallest community of the three and a 19-month-old core package.
If none of that decides it, pick on the first row of the first table. Everything else in this comparison is secondary to whether you want coordinates or an image.
For a worked example of the same measure-the-tarball approach applied to a different React decision, see our list virtualization comparison.
Method
Every figure above was read on 1 October 2026 from primary sources: registry.npmjs.org for versions, dependencies, peer ranges and unpacked sizes; the npm downloads API for install counts; the published .tgz tarballs for licence files, type definitions, stylesheet sizes and the occurrence scans; and the GitHub REST API for stars, branches, default-branch commits and the issue and pull-request split. Gzipped sizes are the ESM entry point named by each package's own module or exports field, compressed at level 9. No figure here was taken from another article.
Written by
Aaron BrickAaron Brick curates the ShipGarden gallery, where we test open-source building blocks so we can own the stack that funds the life.
Frequently asked questions
Does react-image-crop still require you to write the canvas code yourself?
No, not since version 11.1.0, published 21 June 2026. That release added two exported functions, cropToCanvas and cropToImg. cropToImg creates the canvas, applies your scale and rotation, converts the result with toBlob and returns an object URL, revoking the previous one it issued. Scanning the published tarballs version by version, 11.0.10 from April 2025 contains neither function and 11.1.0 contains both. Most comparison articles still describe the older behaviour.
Which of these three gives you the cropped image rather than just coordinates?
Two of them now. react-image-crop does, through cropToCanvas and cropToImg since 11.1.0. react-advanced-cropper always has, through getCanvas(). react-easy-crop does not: a case-insensitive scan of every shipped type and runtime file in version 6.2.3 finds zero occurrences of canvas, drawImage, toBlob, toDataURL or OffscreenCanvas, and the same scan of its v7 canary from 5 September 2026 also finds zero. The getCroppedImg function people associate with it is example code in its documentation, not an export.
Which one is actually the smallest?
react-image-crop, at 19,684 bytes for its ESM entry point and 5,028 bytes gzipped, with no runtime dependencies. react-easy-crop is 38,213 bytes and 8,148 gzipped. react-advanced-cropper is 81,758 bytes and 14,161 gzipped. Do not use npm's unpacked size for this: it reports react-advanced-cropper at 1.1 MB, which is mostly themes and build targets your bundler never loads.
Why does react-cropper look the smallest on npm when it is not?
Because npm's unpacked size measures only the package you install. react-cropper is a 2,944 byte wrapper, so it reports 20,486 bytes unpacked, but it declares Cropper.js version 1.5.13 or compatible as a runtime dependency. Installing it pulls Cropper.js 1.6.3, whose ESM entry is 108,396 bytes and 23,294 gzipped. The realistic total is about 111 KB raw and 24.6 KB gzipped, making the apparently lightest option the heaviest of the four.
Is react-cropper abandoned, given Cropper.js has moved to version 2?
The wrapper is dormant and its dependency is not. react-cropper last published in April 2023, last committed in September 2023, and eleven of its fourteen branches are automated dependency bots. But Cropper.js published 1.6.3 on 23 August 2026, the same day as 2.2.0, so the version 1 line the wrapper pins is still maintained. That is milder than an abandoned stack. The real limitation is that Cropper.js 2 is a custom-elements rewrite the wrapper's component model cannot reach.
Are all three MIT licensed?
No. react-easy-crop ships plain MIT. react-image-crop is ISC, which is permissive and broadly equivalent but is a different identifier, and some automated policy checks use an explicit allowlist. react-advanced-cropper is listed as MIT on npm and as NOASSERTION on GitHub, because its licence file opens with a scope line before the MIT text: the source code is MIT, the documentation content belongs to the author and the photos to their owners. The MIT body is unmodified, so this does not restrict shipping the library, only copying its documentation or demo images. Its core package, advanced-cropper 0.17.1, ships no licence file at all.
More from the garden
react-virtuoso vs TanStack Virtual vs react-window: the 2026 Next.js comparison
All three shipped a release in September 2026 and all three are MIT. What separates them is how much of the component they hand you: five prebuilt components, two, or none at all. The library everyone quotes as 5KB is measured here at eleven times that.
Sonner vs react-hot-toast vs react-toastify for Next.js in 2026
Three React toast libraries whose reputations are all slightly wrong. Read from the npm registry, the published tarballs, the GitHub API and the live shadcn registry on 23 September 2026: the most downloaded one is the heaviest, the one with the steepest search decline shipped a release seven days ago, and the oldest has the best accessibility.
tsup vs unbuild vs bunchee: TypeScript package bundlers in 2026
Three zero-config bundlers for shipping a TypeScript package, measured against live registry and repository state on 28 September 2026. One carries a maintainer deprecation notice, one has not released in over a year, and one requires Node 22.12. Plus what Vercel's turborepo actually uses, which is not what the usual citation says.