Preview
Use mouse wheel or pinch gesture to zoom. Drag with mouse or touch, or use arrow keys to pan the image within the crop area.
Installation
CLI
npx shadcn@latest add https://kelvinmai.io/r/image-cropper.json
Manual
Install the following dependencies
npm install clsx tailwind-merge @origin-space/image-cropper
Add a classname utility function
import { clsx, type ClassValue } from 'clsx';import { twMerge } from 'tailwind-merge';export const cn = (...inputs: ClassValue[]) => {return twMerge(clsx(inputs));};
Copy and paste the following code into your project
components/image-cropper.tsx
'use client';import * as React from 'react';import { Cropper } from '@origin-space/image-cropper';import { cn } from '@/lib/utils';export type Area = { x: number; y: number; width: number; height: number };export const ImageCropper: React.FC<React.ComponentProps<typeof Cropper.Root>> = ({ className, children, ...props }) => {return (<Cropper.Rootdata-slot='cropper'className={cn('relative flex w-full cursor-move touch-none items-center justify-center overflow-hidden focus:outline-none',className,)}{...props}><Cropper.Descriptiondata-slot='cropper-description'className='sr-only'/>{children}</Cropper.Root>);};export const ImageCropperImage: React.FC<React.ComponentProps<typeof Cropper.Image>> = ({ className, ...props }) => {return (<Cropper.Imagedata-slot='cropper-image'className={cn('pointer-events-none h-full w-full object-cover',className,)}{...props}/>);};export const ImageCropperArea: React.FC<React.ComponentProps<typeof Cropper.CropArea>> = ({ className, ...props }) => {return (<Cropper.CropAreadata-slot='cropper-crop-area'className={cn('pointer-events-none absolute border-3 border-white shadow-[0_0_0_9999px_rgba(0,0,0,0.3)] in-[[data-slot=cropper]:focus-visible]:ring-[3px] in-[[data-slot=cropper]:focus-visible]:ring-white/5',className,)}{...props}/>);};
Update the import paths to match your project setup
Usage
import { ImageCropper } from '@/components/ui/image-cropper';export default function ColorPickerDemo() {const [cropData, setCropData] = React.useState<Area | null>(null);return (<ImageCropper image='https://image.url' onCropChange={setCropData}><ImageCropperImage /><ImageCropperArea /></ImageCropper>);}
API Reference
Props
Name | Type | Default | Description |
---|---|---|---|
image | string | Required | URL of the image to crop. |
children | React.ReactNode | Required | Should include Cropper.Image , Cropper.CropArea , and Cropper.Description . |
aspectRatio | number | 1 | The desired width/height aspect ratio (e.g., 1 , 1.5 , 4 / 3 , 16 / 9 ). |
cropPadding | number | 25 | Minimum padding (in pixels) between the crop area edges and the container edges. |
minZoom | number | 1 | Minimum zoom level (1 = 100% original size relative to crop area). |
maxZoom | number | 3 | Maximum zoom level. |
zoomSensitivity | number | 0.005 | Multiplier for mouse wheel delta to control zoom speed. |
keyboardStep | number | 10 | Number of pixels to pan the image when using arrow keys. |
zoom | number | undefined | Controlled zoom level. If provided, component zoom state is controlled externally. |
onCropChange | (pixels: Area | null) => void | undefined | Callback function triggered whenever the crop area changes. Receives pixel data or null if invalid. |
onZoomChange | (zoom: number) => void | undefined | Callback function triggered when the zoom level changes interactively. Essential for controlled zoom prop. |
The Area
object received by onCropChange
contains the following properties relative to the original image dimensions:
Name | Type | Description |
---|---|---|
x | number | The x-coordinate of the top-left corner of the cropped area. |
y | number | The y-coordinate of the top-left corner of the cropped area. |
width | number | The width of the cropped area in pixels. |
height | number | The width of the cropped area in pixels. |
Examples
With Mask
Use mouse wheel or pinch gesture to zoom. Drag with mouse or touch, or use arrow keys to pan the image within the crop area.
With Preview
Use mouse wheel or pinch gesture to zoom. Drag with mouse or touch, or use arrow keys to pan the image within the crop area.
Image preview