Preview
Loading...
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
Loading...
With Preview
Loading...
