Image Cropper

Pro

Photo crop screen where you pan and pinch under a fixed frame that never shows a gap. Straighten, rotate, flip and switch aspect ratios, with a round crop for profile photos.

Preview

Installation

npx @lumioui/cli add pro/image-cropper

Usage

import { DEFAULT_ASPECTS, ImageCropper } from "@/components/ui/image-cropper/image-cropper";
<ImageCropper />

Also exported: DEFAULT_ASPECTS.

Examples

Banner 3:1

A shop owner's banner editor, in ink.

Photo edit

A photo editor's crop tool in amber.

Profile photo

A social app's new-avatar step in coral.

API reference

ImageCropper

Prop Type Default
source* ImageSourcePropType

The photo to crop.

—
height* number } —
imageSize { width: number

Intrinsic pixel size. Resolved with Image.getSize when omitted.

—
aspect CropAspect

Frame aspect (width / height) or "original". Changing it morphs the frame in place. Default "original".

—
rotation number

Controlled quarter-turn rotation in degrees (multiples of 90).

—
defaultRotation number

Uncontrolled initial rotation. Default 0.

—
onRotationChange (rotation: number) => void —
straighten number

Controlled straighten angle in degrees, −45…45.

—
defaultStraighten number

Uncontrolled initial straighten. Default 0.

—
onStraightenChange (deg: number) => void

Fires when the straighten ruler settles on a whole degree (and on flip / reset).

—
flipped boolean

Controlled horizontal mirror.

—
defaultFlipped boolean

Uncontrolled initial mirror. Default false.

—
onFlippedChange (flipped: boolean) => void —
ruler boolean

Show the straighten ruler under the photo. Default false.

—
shape "rect" | "circle"

rect (default) or circle — a round avatar mask (forces a square frame).

—
grid "auto" | "always" | "never"

Rule-of-thirds grid: auto shows while touching (default), always, or never.

—
maxZoom number

Maximum zoom over the cover scale. Default 5.

—
inset number

Inset between the stage edge and the frame. Default 20.

—
onCropChange (crop: CropRect) => void

Fires with the crop each time the pose settles.

—
onInteractionChange (active: boolean) => void

Fires when a pan, pinch or straighten starts / ends.

—
committed boolean

The crop is confirmed: the mask closes, the framed photo lifts and gestures lock. Back to false reopens the editor. Default false.

—
onCommitSettled () => void

Fires once the commit has landed and held (~850ms after committed) — the moment to move on.

—
accessibilityLabel string

Screen-reader description. Default "Crop photo".

—
className string —

StraightenDial

Prop Type Default
value* number

Angle in degrees.

—
onValueChange* (deg: number) => void

Fires when the ruler settles on a whole degree (drag release, tap on the readout, screen-reader step).

—
range number

Range either side of zero. Default 45.

—
tone "auto" | "light"

auto follows the theme; light draws white ink for a black stage. Default auto.

—
disabled boolean —
live SharedValue<number>

Written every frame with the live angle — link it to a stage on the UI thread.

—
activity SharedValue<number>

Eases 0 → 1 while the ruler is in use (for guides that follow it).

—
onActiveChange (active: boolean) => void

Fires when a drag starts and when it has settled.

—
className string —

AspectPicker

Prop Type Default
value* CropAspect —
onValueChange* (aspect: CropAspect) => void —
options AspectOption[]

Presets, laid out in equal widths. Default Original / Square / 4:5 / 16:9.

—
disabled boolean —
className string —

CropTool

Prop Type Default
kind* "rotate" | "flip"

rotate turns 90° counter-clockwise; flip mirrors. The glyph performs it.

—
onPress* () => void —
disabled boolean —
accessibilityLabel string —
className string —

CropReset

Prop Type Default
changed* boolean

The crop differs from the untouched photo — "Reset" ignites in place of the label.

—
onPress* () => void —
label string

Shown while nothing has changed. Default "Crop".

—
resetLabel string

Default "Reset".

—
disabled boolean —
className string —