Headless image cropper for React and plain TypeScript, with the feel of the crop tool in iOS Photos. Crop a photo, straighten it with a dial, rotate, flip and zoom it, then export the result.
- Unstyled parts you compose and style yourself, plus an optional stylesheet.
- Pinch, twist, wheel and trackpad zoom, with a rubber band at the edges.
- No empty corners at any angle, on screen and in the exported file.
- Full keyboard control, screen reader labels and reduced motion.
- Export in a worker from the full-resolution photo, or crop on your server with sharp. A cropped JPEG never comes out at a higher quality than the photo it came from.
- Opens SVG too, after a check that refuses a file that would freeze the page.
- Zero runtime dependencies. React 18.2 and 19 from one build, and a plain TypeScript API for everything else.
Docs, demos and the API live at zriz.dev.
pnpm add @zriz/react @zriz/core"use client";
import * as Cropper from "@zriz/react/cropper";
import "@zriz/react/styles.css";
export const PhotoCropper = ({ photo }: { photo: File }) => (
<Cropper.Root
src={photo}
onValueCommit={(value, details) => console.log(details.pixelCrop)}
>
<Cropper.Viewport style={{ maxWidth: 400, height: 300, padding: 24 }}>
<Cropper.Image />
<Cropper.Mask />
<Cropper.Area aria-label="Crop area">
<Cropper.Handle position="top-left" />
<Cropper.Handle position="top-right" />
<Cropper.Handle position="bottom-right" />
<Cropper.Handle position="bottom-left" />
</Cropper.Area>
</Cropper.Viewport>
<Cropper.Dial aria-label="Straighten" style={{ maxWidth: 361 }}>
<Cropper.DialTicks />
</Cropper.Dial>
</Cropper.Root>
);Quick start goes from here to a file picker and the crop in pixels.
| Package | |
|---|---|
@zriz/react |
Unstyled React parts and hooks |
@zriz/core |
Geometry, the coverage solver, DOM binders, export |
Open an issue. I don't take pull requests. CONTRIBUTING.md explains why and what helps most instead.
MIT