# Image Cropper (/docs/components/image-cropper)



<ComponentPreview name="image-crop" />

## Installation [#installation]

<Tabs items="[&#x22;Command&#x22;, &#x22;Manual&#x22;]">
  <Tab value="Command">
    <CodeBlockTabs defaultValue="npm">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="npm">
          npm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="pnpm">
          pnpm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="yarn">
          yarn
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="bun">
          bun
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="npm">
        ```bash
        npx shadcn@latest add @uploadcn/image-cropper
        ```
      </CodeBlockTab>

      <CodeBlockTab value="pnpm">
        ```bash
        pnpm dlx shadcn@latest add @uploadcn/image-cropper
        ```
      </CodeBlockTab>

      <CodeBlockTab value="yarn">
        ```bash
        yarn dlx shadcn@latest add @uploadcn/image-cropper
        ```
      </CodeBlockTab>

      <CodeBlockTab value="bun">
        ```bash
        bun x shadcn@latest add @uploadcn/image-cropper
        ```
      </CodeBlockTab>
    </CodeBlockTabs>
  </Tab>

  <Tab value="Manual">
    Install [Upload](/docs/components/upload) first, then copy:

    <ComponentSource name="image-cropper" />
  </Tab>
</Tabs>

## Usage [#usage]

```tsx
import { ImageCropper } from "@/components/ui/image-cropper"
import { useCropQueue } from "@/hooks/use-crop-queue"
```

```tsx
const crops = useCropQueue()

<Upload adapter={adapter} accept="image/*" transform={crops.request}>
  …
</Upload>
<ImageCropper file={crops.current} aspect={1} onCrop={crops.complete} onCancel={crops.skip} />
```

The crop UI is [react-easy-crop](https://github.com/ValentinH/react-easy-crop) (touch, pinch, wheel and keyboard). Rendering uses `transformImage` from `@uploadcn/core/image`: EXIF orientation is applied and metadata is stripped. Install `use-crop-queue` to use it inside the upload pipeline.

## Props [#props]

<TypeTable
  type="{
  file: {
    type: &#x22;File | null&#x22;,
    description: &#x22;The dialog is open while a file is set.&#x22;,
  },
  onCrop: { type: &#x22;(file: File) => void&#x22; },
  onCancel: { type: &#x22;() => void&#x22; },
  aspect: { type: &#x22;number&#x22;, default: &#x22;1&#x22;, description: &#x22;Width / height.&#x22; },
  cropShape: { type: '&#x22;rect&#x22; | &#x22;round&#x22;', default: '&#x22;rect&#x22;' },
  output: {
    type: &#x22;ImageTransformOptions&#x22;,
    description: &#x22;Size, type and quality of the result (default max 2048px).&#x22;,
  },
  title: { type: &#x22;ReactNode&#x22; },
  description: { type: &#x22;ReactNode&#x22; },
}"
/>
