Image Cropper

Crop, zoom, and rotate images. Supports Reactive Forms and Signal API.

Basic Cropper (16:9)

Default 16:9 aspect ratio. Drag to crop, zoom with +/-, rotate with the slider.

Cropped Result

Cropped preview

0 × 0 px

<rui-cropper
  [src]="'https://picsum.photos/800/600'"
  [rotationMin]="-10"
  [rotationMax]="10"
  [(croppedImage)]="cropped"
/>

Square 1:1 (Fixed Aspect)

Fixed 1:1 aspect ratio in a 320px square container. No aspect dropdown shown.

<div class="w-80 h-80">
  <rui-cropper
    [src]="'...'"
    [aspectRatio]="'1:1'"
  />
</div>

Free Aspect Ratio

Container has 4:3 aspect ratio. Aspect ratio selector is visible.

<div class="aspect-[4/3] max-w-2xl">
  <rui-cropper
    [src]="'...'"
    [aspectRatio]="'free'"
  />
</div>

Fixed Width with Sidebar

Set a fixed width like [width]="600" so the cropper size stays constant regardless of sibling layout changes.

<rui-cropper
  [src]="'...'"
  [width]="600"
  [aspectRatio]="'16:9'"
/>

Error Handling

When the image fails to load, a loadError event is emitted.

<rui-cropper
  [src]="imageUrl"
  (loadError)="handleError($event)"
/>

Dynamic Configuration

Change aspect ratio, format, quality, and output size on the fly.

<rui-cropper
  [src]="'...'"
  [aspectRatio]="aspect()"
  [outputFormat]="'image/png'"
  [outputQuality]="0.92"
  [(croppedImage)]="cropped"
/>

Toolbar Positions

The toolbar can be placed at top, bottom (default), left, or right.

Bottom (default)

Top

Left

Right

<rui-cropper toolbarPosition="top" />

<rui-cropper toolbarPosition="bottom" />

<rui-cropper toolbarPosition="left" />

<rui-cropper toolbarPosition="right" />

Constrain to Image

When constrainToImage is true (default), the crop selection cannot leave the original image area — even when zooming out or rotating.

Try zooming out (-) or rotating (r). The crop stays inside the image.

<mat-slide-toggle [checked]="constrain()" (change)="constrain.set($event.checked)">
  constrainToImage: {{ constrain() }}
</mat-slide-toggle>

<rui-cropper
  [src]="'...'"
  [constrainToImage]="constrain()"
  [aspectRatio]="'free'"
  [rotationMin]="-180"
  [rotationMax]="180"
/>

Template-driven Form

Using ngModel with the cropper. The model value is the cropped image data URL.

Model value: none

<rui-cropper
  [src]="'https://picsum.photos/800/600'"
  ngModel
  name="cropperModel"
  #cropperModelRef="ngModel"
  [rotationMin]="-10"
  [rotationMax]="10"
/>

Reactive Form

Using formControl with the cropper. The control value is the cropped image data URL.

Control value: none

Control enabled: true

<rui-cropper
  [src]="'https://picsum.photos/800/600'"
  [formControl]="cropControl"
  [rotationMin]="-10"
  [rotationMax]="10"
/>

Signal Form

Using model() signal directly — no FormsModule or ReactiveFormsModule needed.

Signal value: none

<rui-cropper
  [src]="'https://picsum.photos/800/600'"
  [(croppedImage)]="cropped"
  [rotationMin]="-10"
  [rotationMax]="10"
/>