<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# ImageCropper

A dialog for cropping a photo to a shape before it is used: drag the photo (or move it the way the arrow keys point) to choose what shows in the frame, zoom with the slider (or Plus and Minus), and Save hands the cropped image to `onCrop` as a `File`, ready for a form or an upload. The frame is a rectangle of `aspect`, or a circle for a profile photo. It always opens as a centered dialog, so dragging the photo never drags the dialog away.

```tsx
import { ImageCropper } from "@/components/ouro/image-cropper/image-cropper";
```

## Example

```tsx
<ImageCropper open={file !== null} onOpenChange={(open) => !open && setFile(null)} image={file} shape="circle" onCrop={upload} />
```

## Use instead when

- Use `ImageField` with `crop` instead to pick a photo and crop it in one field, and `FileField` for files that need no cropping.

## Props

Type: `ImageCropperProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `aspect` | `number` | `1` | The crop's width divided by its height: `1` square, `16 / 9` wide. |
| `image` (required) | `File \| Blob \| string \| null` |  | The image to crop: a `File` from a picker, a `Blob`, or a URL the page may read pixels from (same origin or CORS). |
| `labels` | `ImageCropperLabels` |  | The words it shows and says. |
| `onCrop` (required) | `(file: File) => void` |  | Called with the cropped image, as a `File`, when the person saves. The dialog then closes. |
| `onError` | `((reason: ImageCropperFailure) => void)` |  | Called when the image cannot be opened or the crop cannot be saved. The cropper shows and announces `labels.openError` or `labels.saveError` itself; close it or offer another image. |
| `onOpenChange` (required) | `(open: boolean) => void` |  | Called when it opens or closes: after Save, Cancel, Escape or the close button. |
| `open` (required) | `boolean` |  | Whether the cropper's dialog is open. |
| `outputWidth` | `number` | `1024` | The saved image's width in pixels; its height follows `aspect`. |
| `shape` | `"circle" \| "rect"` | `"rect"` | `circle` shows a round frame for a profile photo; the saved image is still the square around it. |
| `title` | `string` | `"Crop photo"` | The dialog's title. |
| `type` | `"image/jpeg" \| "image/png" \| "image/webp"` | `"image/jpeg"` | The saved image's format. |

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `aspectRatio`: Not a prop. The shape is `aspect`, width over height: `aspect={16 / 9}`.
- `onChange`: Not a prop. The cropped image comes to `onCrop`: `<ImageCropper onCrop={(file) => …} />`.
- `round`: Not a prop. Ouro UI uses `shape`: `<ImageCropper shape="circle" />`.
- `src`: Not a prop. The image is `image`: `<ImageCropper image={file} />`.

## Types

### `ImageCropperFailure`

What went wrong: `open`, the browser cannot show the image (a format it cannot decode, or an address it may not read); `save`, it cannot encode the crop.

```ts
type ImageCropperFailure = "open" | "save";
```

### `ImageCropperLabels`

The words the cropper shows and says, for apps in other languages.

```ts
interface ImageCropperLabels {
  /** @default "Save" */
  save?: string | undefined;
  /** @default "Cancel" */
  cancel?: string | undefined;
  /** The zoom slider's label. @default "Zoom" */
  zoom?: string | undefined;
  /** The crop area's name for screen readers. @default "Photo to crop" */
  area?: string | undefined;
  /** How to move the photo, read with the crop area. @default "Drag the photo, or move it with the arrow keys, to choose what shows. Plus and minus zoom." */
  instructions?: string | undefined;
  /** Shown and announced when the browser cannot open the image. @default "This photo could not be opened. Choose another one." */
  openError?: string | undefined;
  /** Shown and announced when the browser cannot save the crop; Save can be tried again. @default "The photo could not be saved. Try again." */
  saveError?: string | undefined;
}
```
