shadcn.io is not affiliated with official shadcn/ui
Components
Free
Image Cropper for React
Pick the part of a photo to keep, lock the aspect or a circle, and get that region back. For React with Base UI, when the crop is something you will store.
Framework
UI library
Base UI does not include this primitive, so this page uses the Ark UI component. The visuals match the Ark UI version.
Frame a photo with a draggable rectangle or circle. Lock the aspect when the crop should stay fixed.
Use it when you will store that region later, like a profile photo. A click that only magnifies is Image Zoom. In React, Base UI puts handles on the selection so the keys can nudge it.
Installation
Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.
aspectRatio is width divided by height, so 16 / 9 stays widescreen while the selection is resized. Lock it for a cover, a video poster, or any slot with a fixed frame, and omit it when the person should be free to drag a tall crop or a wide one. A circle is not a ratio. Set cropShape when the mask itself has to be round.
Circle Crop
cropShape="circle" rounds the selection, which is what an avatar upload wants, and ImageCropperSelection still draws the grid and the handles. Use a circle only when the destination is round, because a rectangular crop rounded later with CSS will not match the file you store. The aspect can stay free. The shape is what the mask follows.
Controlled Zoom
zoom is held in state so the buttons and the wheel share one number. Those buttons step a quarter at a time and stop between zero and three. Take control when the page needs a visible zoom in and zoom out, or when another control must show the scale. Omit zoom and the cropper owns it, starting from defaultZoom.
Fixed Crop Area
fixedCropArea pins the selection and asks the person to pan and zoom the photo under it. Use that for an avatar or a cover whose output size is already decided, where the only choice is which part of the picture lands inside. Leave it off when they should draw the rectangle themselves. Min and max size are the softer limit, for a box that can still move.
Initial Crop
initialCrop takes x, y, width, and height, so the first rectangle is not the automatic one. Use it to reopen a saved crop or to start on a known region, and read later drags from onCropChange, which reports those same fields. The component never uploads the file. Your own submit handler sends the image plus that rectangle.
Min Max Size
minWidth, minHeight, maxWidth, and maxHeight keep the selection from collapsing or swallowing the frame, and this one stays between 80 pixels and a box of 280 by 160. The minimums default to 40 if you set nothing. Use limits when a tiny crop would be useless or a huge one would break the frame you print into. A fixed crop area is stricter, because that box cannot move at all.
Zoom Limits
minZoom and maxZoom cap the wheel. Here the photo can shrink to half and grow only to twice, where the defaults are 1 and 5. Drop the minimum when the picture is larger than the viewport, and keep the maximum tight when a deep zoom would export soft. These props only bound the range, while the controlled demo is about who stores the number.
FAQ
How do I lock an Image Cropper's aspect ratio?
Set aspectRatio to width divided by height, such as 16 / 9, as the Aspect Ratio demo does, and omit it when the selection can be resized freely. Set cropShape to circle for a round crop, or leave the default rectangle. The selection uses data-shape so the circle is fully rounded. ImageCropperSelection draws the grid and the handles for you.
How do I control Image Cropper zoom in React?
Keep the zoom number in state when buttons must zoom in and out, and pass it back so the wheel and the buttons agree. Omit zoom and the cropper owns it, with defaultZoom as the start, minZoom defaulting to 1, and maxZoom defaulting to 5, as the Zoom Limits demo tightens.
onZoomChange receives details.zoom, and you pass that number as zoom.
How do I stop an Image Cropper selection from growing?
Set minWidth, minHeight, maxWidth, and maxHeight on ImageCropper. The minimums default to 40. Set fixedCropArea when the selection must stay put and people pan and zoom the image instead, as the Fixed Crop Area demo does. flip takes horizontal and vertical booleans, and rotation is degrees, if you need those transforms too.
Can I use an Image Cropper from the keyboard?
Yes, arrow keys nudge the Image Cropper selection by nudgeStep, which defaults to 1 pixel, while Shift and Ctrl or Cmd use nudgeStepShift and nudgeStepCtrl. Alt with an arrow resizes from the bottom or right handle, and plus zooms in while minus zooms out. The selection is the focusable part, so do not hide it if keyboard users must crop.
How do I read the crop from an Image Cropper?
Pass initialCrop with x, y, width, and height when the first rectangle should not be the automatic one. onCropChange then receives details.crop with those same fields as the user drags. Image Cropper does not upload or replace the file. Send the original image plus that rectangle from your own submit handler.
How do I restyle an Image Cropper?
Edit the Image Cropper file in your ui folder. The root sets --cropper-accent, --cropper-handler-size, and --cropper-handler-width, and the handles and grid read them. data-dragging and data-panning mark an active gesture, and data-shape is circle or rectangle. The image itself is data-slotimage-cropper-image and should keep an alt.
Should I use Image Cropper or Image Zoom?
Use Image Cropper when people must choose a rectangle or a circle and you need that region. Use Image Zoom when a click should only magnify the picture, SVG, or diagram, with nothing to export. Cropper is the editor and Zoom is a viewer, so they solve different tasks, and a page can use both.
How do I install Image Cropper in React?
Run the command in the Installation section above. It adds ImageCropper, ImageCropperImage, and ImageCropperSelection to your ui folder, and the selection includes the grid and handles. Install from that section rather than pasting a partial tree, and put src and alt on ImageCropperImage, as Usage does.
The command uses the shadcn CLI.
API Reference
ImageCropper
<div>data-slot="image-cropper"
PropType
flip?object
The controlled flip state of the image.
Type
{ horizontal: boolean; vertical: boolean }
defaultFlip?object
The initial flip state to apply to the image.
Type
{ horizontal: boolean; vertical: boolean }
Default
{ horizontal: false, vertical: false }
onFlipChange?(details: FlipChangeDetails) → void
Callback fired when the flip state changes.
Type
(details: FlipChangeDetails) → void
Parameters
details – { flip: FlipState }
Returns
void
rotation?number
The controlled rotation of the image in degrees (0 - 360).
defaultRotation?number
The initial rotation to apply to the image in degrees.
The aspect ratio to maintain for the crop area (width / height).
For example, an aspect ratio of 16 / 9 will maintain a width to height ratio of 16:9.
If not provided, the crop area can be freely resized.
cropShape?"rectangle" | "circle"
The shape of the crop area.
Type
"rectangle" | "circle"
Default
"rectangle"
dir?"ltr" | "rtl"
The document's text/writing direction.
Type
"ltr" | "rtl"
Default
"ltr"
fixedCropArea?boolean
Whether the crop area is fixed in size and position.
The aspect ratio to maintain for the crop area (width / height).
For example, an aspect ratio of 16 / 9 will maintain a width to height ratio of 16:9.
If not provided, the crop area can be freely resized.
cropShape?"rectangle" | "circle"
The shape of the crop area.
Type
"rectangle" | "circle"
Default
"rectangle"
fixedCropArea?boolean
Whether the crop area is fixed in size and position.