First-class React wrapper with useCrop hook for state management.
npm install @imazen/crop-image-react
Peer dependencies: react >= 18, react-dom >= 18. The web component is auto-registered on import.
import { CropImage } from '@imazen/crop-image-react';
function App() {
return (
<CropImage
src="/photo.jpg"
aspectRatio="16/9"
onChange={(detail) => console.log(detail.selection)}
onCommit={(detail) => console.log(detail.riapi.querystring)}
/>
);
}
useCrop HookFor controlled state management, useCrop tracks the current selection, committed RIAPI querystring, and provides a reset function.
import { CropImage, useCrop } from '@imazen/crop-image-react';
function CropEditor() {
const crop = useCrop();
return (
<div>
<CropImage
src="/photo.jpg"
aspectRatio="16/9"
onChange={crop.onChange}
onCommit={crop.onCommit}
/>
<p>Querystring: {crop.querystring}</p>
<button onClick={crop.reset}>Reset</button>
</div>
);
}
useCrop Options| Option | Type | Description |
|---|---|---|
initialSelection | CropSelection | Starting crop state. Defaults to 10% inset on all sides. |
useCrop Return Value| Property | Type | Description |
|---|---|---|
selection | CropSelection | Current crop + pad state |
onChange | (detail) => void | Pass to <CropImage onChange> |
onCommit | (detail) => void | Pass to <CropImage onCommit> |
setSelection | (sel) => void | Manually update the selection |
reset | () => void | Reset to initial selection |
querystring | string | Last committed RIAPI querystring |
params | Record<string, string> | Last committed RIAPI params object |
The wrapper accepts all web component attributes as camelCase props, plus callback props.
| Prop | Type | Description |
|---|---|---|
src | string | Image URL (required) |
mode | 'crop' | 'crop-pad' | Crop mode |
aspectRatio | string | Aspect ratio constraint |
shape | 'rect' | 'circle' | Frame shape (circle forces 1:1) |
maxZoom | number | Maximum zoom level |
aspectRatios | Array<{w, h, label?}> | Array of ratio choices |
minWidth | number | Min crop width (source px) |
minHeight | number | Min crop height (source px) |
maxWidth | number | Max crop width (source px) |
maxHeight | number | Max crop height (source px) |
value | CropSelection | Controlled selection value |
name | string | Form field name |
adapter | string | RIAPI adapter name |
disabled | boolean | Disable interaction |
onChange | (detail) => void | Called on every drag move |
onCommit | (detail) => void | Called when drag ends |
Use a ref to access the underlying DOM element and its selection property:
import { useRef } from 'react';
import { CropImage, type CropImageRef } from '@imazen/crop-image-react';
function App() {
const ref = useRef<CropImageRef>(null);
const logSelection = () => {
console.log(ref.current?.selection);
console.log(ref.current?.element);
};
return (
<>
<CropImage ref={ref} src="/photo.jpg" />
<button onClick={logSelection}>Log Selection</button>
</>
);
}
All types are exported from the package:
import type {
CropImageProps,
CropImageRef,
CropChangeDetail,
CropRect,
PadRect,
CropSelection,
AspectRatio,
CropConfig,
} from '@imazen/crop-image-react';
import { CropImage, useCrop } from '@imazen/crop-image-react';
import type { CropSelection } from '@imazen/crop-image-react';
function PhotoCropper({ imageUrl }: { imageUrl: string }) {
const crop = useCrop();
const handleSave = () => {
// Send the RIAPI querystring to your image server
fetch(`/api/resize?src=${imageUrl}${crop.querystring}`)
.then(res => res.blob())
.then(blob => {
// Use the cropped image
});
};
return (
<div>
<CropImage
src={imageUrl}
aspectRatio="4/3"
edgeSnap={0.03}
adapter="imageflow"
onChange={crop.onChange}
onCommit={crop.onCommit}
style={{ maxWidth: '600px' }}
/>
<div>
<pre>{crop.querystring}</pre>
<button onClick={crop.reset}>Reset</button>
<button onClick={handleSave}>Save</button>
</div>
</div>
);
}
SSR note: The web component registration is guarded with typeof window !== 'undefined', so the import is safe for Next.js and other SSR frameworks. The element renders as an empty custom element during SSR and hydrates on the client.