react-cropper

A React component wrapper around Cropper.js for drag, zoom, and rotate image cropping.

Library
npm
v2.3.3
2,080stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
46/100Fair
Development Activity0
Maintenance20
Community64
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
68/100Good
Architecture70
Code Quality78
Innovation45
Learning Curve80

react-cropper wraps the popular Cropper.js library as a declarative React component, letting apps drop in interactive image cropping, resizing, rotating, and zooming without wiring up imperative DOM APIs by hand. It exposes Cropper.js’s full option surface as React props, forwards a ref to the live Cropper instance so consumers can call its native methods directly, and re-initializes cleanly when the image src changes.

The component handles lifecycle concerns that are easy to get wrong when integrating an imperative library into React: it constructs the Cropper instance on mount, destroys it on unmount to avoid leaks, and applies default option values (scale, zoom, rotation, enabled state) through a dedicated ready callback rather than fighting React’s render cycle. This makes it a common building block wherever an app needs avatar upload cropping, image editing tools, or any UI that lets a user select and crop a region of an image before submitting it.

What You Get

  • A Cropper React component (default and named export) that accepts all Cropper.js options as props
  • Typed ReactCropperElement and ReactCropperProps TypeScript definitions shipped with the package
  • Ref forwarding to the underlying Cropper.js instance for calling native methods like getCroppedCanvas()
  • An onInitialized callback that fires once the Cropper.js instance is ready to use
  • Automatic re-cropping/reset when the src prop changes, without manual teardown code
  • Convenience props (scaleX, scaleY, enable, zoomTo, rotateTo) applied automatically on init via applyDefaultOptions

Common Use Cases

  • Avatar and profile photo upload flows that need crop-before-submit
  • Image editing tools that let users select an aspect-ratio-constrained crop region
  • Admin/CMS interfaces where uploaded images must be cropped to a fixed size before saving
  • E-commerce product image editors that need zoom, rotate, and crop before publishing

Under The Hood

Architecture The package is intentionally small: src/react-cropper.tsx defines a single forwardRef component that owns one job — bridging Cropper.js’s imperative constructor/instance API into React’s declarative render and effect model. A useCombinedRefs hook merges the caller’s forwarded ref with an internal ref so both the consumer and the component share the same underlying <img> node. Three useEffect hooks separate concerns cleanly: one constructs the Cropper.js instance on mount and destroys it on unmount, one reacts to src prop changes by calling the instance’s reset().clear().replace() chain instead of tearing down and rebuilding, and one re-applies zoomTo when that prop changes after init. src/utils.ts holds a single cleanImageProps helper that strips Cropper.js-only option keys out of the props passed through to the underlying <img> element, keeping the DOM output free of invalid HTML attributes. There is no internal state management beyond refs — all cropper state lives inside the Cropper.js instance itself, which keeps the wrapper thin but means most runtime capability is only reachable imperatively via the ref.

Tech Stack Written in TypeScript and built with Rollup (rollup.config.mjs) into UMD and ES module bundles, with rollup-plugin-dts generating a separate .d.ts bundle. The only runtime dependency is cropperjs itself; React is a peer dependency (>=17.0.2), so the package rides on whatever React version the consuming app already has. Babel handles JSX/TS transpilation for the build, and the dev server (rollup.config.dev.mjs) uses rollup-plugin-serve for local iteration against the example/ app. No CSS is bundled — consumers are expected to import cropperjs/dist/cropper.css themselves.

Code Quality Test coverage lives in tests/react-cropper.test.tsx using Jest, @testing-library/react, and react-test-renderer, covering ref forwarding (both object and callback refs), the onInitialized callback, src prop changes triggering a re-crop, and the applyDefaultOptions helper’s option-application logic in isolation via mocked Cropper.js methods. ESLint is configured with TypeScript, React, and accessibility plugins (.eslintrc), and Prettier enforces formatting. Naming and typing are consistent throughout the small codebase, and the public API surface (ReactCropperProps, ReactCropperElement) is fully typed against Cropper.js’s own type definitions rather than redefined by hand.

API Design The component’s entire configuration surface is just Cropper.js’s own options object spread across props, so anyone already familiar with Cropper.js needs no new mental model to use this wrapper — the main addition is idiomatic React patterns: a forwarded ref for imperative access, an onInitialized callback in place of a constructor return value, and prop-driven reactivity for src and zoomTo that a raw Cropper.js integration would otherwise require manual effect wiring for. The tradeoff is that most non-trivial operations (getting cropped canvas data, calling crop-box methods) still require reaching into ref.current.cropper rather than being exposed as first-class props, which keeps the wrapper thin but pushes documentation-reading burden onto Cropper.js’s own docs rather than this package’s README.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search