Skip to content
WANCRAFT

F.144Forms & Inputs

Image Cropper

Crop an image with a draggable, resizable box or a fixed frame — aspect presets, zoom, rotate and canvas output.

NewReactCanvasTailwindadvanced

Overview

Image Cropper puts a crop box over an image with eight resize handles, or (in pan mode) a fixed frame you drag the image under. Aspect presets lock the box to free, 1:1, 4:3 or 16:9; the zoom slider, mouse wheel and two-finger pinch zoom between 1× and a maximum; a button rotates in 90° steps. Rule-of-thirds guides appear while you drag. When the crop box is focused, the arrow keys move it, Shift + arrows resize it and + / − zoom. Geometry lives in a ref and is painted straight to the DOM, so gestures never re-render; onChange reports the crop in source pixels once a gesture settles, and the ref returns the result as a canvas or a data URL.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/image-cropper.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/image-cropper.json

Method 02 · Copy and paste

  1. 1. No extra dependencies — React and Tailwind CSS only.
  2. 2. Copy the source from the Code tab into components/ui/image-cropper.tsx.
  3. 3. Import it and adjust props.
Dependencies
None
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { ImageCropper, type ImageCropperHandle } from "@/components/ui/image-cropper";
import { useRef } from "react";

export function ImageCropperExample() {
  const cropper = useRef<ImageCropperHandle>(null);

  return (
    <ImageCropper
      ref={cropper}
      src="/images/portrait.jpg"
      alt="Portrait"
      onChange={(crop) => console.log(crop)}
    />
  );
}

03Props

PropTypeDefaultDescription
srcstring—Image URL (required). Remote images need CORS headers and crossOrigin for the canvas output.
altstring""Describes the image; used in the crop area's accessible name.
aspect"free" | "1:1" | "4:3" | "16:9""free"Initial aspect of the crop; the toolbar presets can change it.
mode"box" | "pan""box"Drag and resize a box over the image, or pan the image under a fixed frame.
maxZoomnumber4Highest zoom (1 = the image fitted to the stage).
grid"drag" | "always" | "never""drag"When to show the rule-of-thirds guides.
showToolbarbooleantrueAspect presets, zoom slider, rotate and reset below the stage.
overlayOpacitynumber0.6Darkness of the area outside the crop (0–1).
heightnumber360Stage height in px; the width follows the container.
accentstring"#FF7448"Handle border and focus ring colour.
labelstring"Image cropper"Accessible name of the cropper group.
crossOrigin"anonymous" | "use-credentials"—Passed to the image element for CORS-enabled remote images.
onChange(crop: CropRect) => void—{ x, y, width, height, rotation } in source pixels, after each gesture, key press or toolbar change settles.
refRef<ImageCropperHandle>—{ getCroppedCanvas({ maxWidth?, maxHeight? }), toDataURL(type?, quality?, options?), getCropRect(), rotate(dir?), reset(), setZoom(z) }.

04Features

  • 01Crop box with eight resize handles, or a fixed frame with the image panned underneath
  • 02Aspect presets: free, 1:1, 4:3, 16:9 — switching keeps the crop's centre and area
  • 03Zoom with the slider, mouse wheel or trackpad pinch (around the cursor) and two-finger touch pinch
  • 04Rotate in 90° steps; output is rotated and cropped in source pixels
  • 05Rule-of-thirds guides while dragging (or always)
  • 06Ref API: getCroppedCanvas() and toDataURL() with optional max size, plus getCropRect, rotate, reset, setZoom
  • 07Geometry painted from a ref — no React render per pointer move
input · draginput · pointerinput · keyboardinput · click

05Accessibility

  • The crop box is a focusable group with a 'crop area' role description and a described keyboard hint.
  • Arrow keys move the box (Shift + arrows resize it); in pan mode they move the image; + and − zoom.
  • Every toolbar control is labelled: aspect presets are toggle buttons with aria-pressed, zoom is a native range input, rotate has an accessible name.
  • A polite live region describes the crop size, position, aspect and zoom whenever a change settles.
  • Visible focus rings on the crop box and every control.

06Limitations

  • Rotation is limited to 90° steps; free-angle straightening is not included.
  • Wheel events over the stage are captured to zoom, so the page does not scroll while the pointer is over the image.
  • Cross-origin images without CORS headers can be cropped visually, but getCroppedCanvas pixels cannot be exported (toDataURL returns null).