# Image cropper (UI SDK): Controller

> `onCropCommit` runs once a drag or key press ends, so save there. A controller from `createImageCropperController()` sets the crop from anywhere.

Canonical: https://hextaui.com/docs/ui-sdk-image-cropper/examples/controlled

Component docs: https://hextaui.com/docs/ui-sdk-image-cropper

## Add this example

```bash
npx shadcn@latest add https://hextaui.com/r/ui-sdk-image-cropper-controlled.json
```

This adds `components/examples/ui-sdk-image-cropper/controlled.tsx` with the Image cropper component and the HextaUI theme tokens.

## Source

```tsx title="components/examples/ui-sdk-image-cropper/controlled.tsx"
"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import {
  createImageCropperController,
  ImageCropper,
  ImageCropperGrid,
  ImageCropperHandles,
  ImageCropperImage,
  ImageCropperSelection,
  ImageCropperViewport,
  type ImageCrop,
} from "@/components/ui/ui-sdk-image-cropper"

const photo =
  "https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=1200&q=80&auto=format&fit=crop"

const start = { x: 120, y: 80, width: 480, height: 480 }

function UiSdkImageCropperControlled() {
  const [cropper] = React.useState(createImageCropperController)
  const [saved, setSaved] = React.useState<ImageCrop | null>(null)

  return (
    <div className="flex w-full max-w-md flex-col gap-3">
      <ImageCropper
        aria-label="Photo"
        src={photo}
        aspectRatio={1}
        defaultCrop={start}
        controller={cropper}
        onCropCommit={setSaved}
      >
        <ImageCropperViewport>
          <ImageCropperImage alt="A rowing boat on a green mountain lake" />
          <ImageCropperSelection>
            <ImageCropperGrid />
            <ImageCropperHandles />
          </ImageCropperSelection>
        </ImageCropperViewport>
      </ImageCropper>
      <div className="flex items-center gap-3">
        <Button
          variant="outline"
          size="sm"
          onClick={() => cropper.setCrop(start)}
        >
          Reset
        </Button>
        <span className="text-sm text-muted-foreground tabular-nums">
          {saved
            ? `Saved ${Math.round(saved.width)} × ${Math.round(saved.height)} at ${Math.round(saved.x)}, ${Math.round(saved.y)}`
            : "Move the crop to save it."}
        </span>
      </div>
    </div>
  )
}

export { UiSdkImageCropperControlled }
```

## Props in this example

### ImageCropper

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | `string` | – |  |
| `defaultCrop` | `ImageCrop` | – |  |
| `onCropCommit` | `(crop, details) => void` | – | Runs once a drag, key press or wheel ends. |
| `aspectRatio` | `number` | – |  |
| `controller` | `ImageCropperController` | – | From createImageCropperController(). |

### ImageCropperImage

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `alt` | `string` | – | Required. |

## More Image cropper examples

- [Avatar](https://hextaui.com/docs/ui-sdk-image-cropper/examples/avatar)
- [Rotate and flip](https://hextaui.com/docs/ui-sdk-image-cropper/examples/rotate-flip)
- [Upload](https://hextaui.com/docs/ui-sdk-image-cropper/examples/upload)
- [Disabled](https://hextaui.com/docs/ui-sdk-image-cropper/examples/disabled)
