Cropper
The Cropper component provides interactive image cropping with a draggable stencil,
zoom, pan, keyboard navigation, and touch/pinch support.
Import
import { Cropper } from '@we-are-singular/svelte-chop-chop'; Props
Image
| Prop | Type | Default | Description |
|---|---|---|---|
src | ImageSource | — | Image URL, data URL, File, Blob, or HTMLImageElement. |
Crop constraints
| Prop | Type | Default | Description |
|---|---|---|---|
aspectRatio | number | { min?: number; max?: number } | null | null | Lock width/height ratio. null allows free crop. |
sizeConstraints | SizeConstraints | — | Object with minWidth, maxWidth, minHeight, maxHeight, minArea. |
cropOutsideImage | boolean | false | Allow the stencil to extend outside the image bounds. |
initialCrop | Partial<Rect> | — | Initial crop rectangle. If omitted, crop fits the image. |
Visual
| Prop | Type | Default | Description |
|---|---|---|---|
grid | 'none' | 'rule-of-thirds' | 'grid' | 'golden-ratio' | 'rule-of-thirds' | Grid overlay style on the stencil. |
gridOnlyActive | boolean | true | Only show the grid while the stencil is being dragged. |
transitions | boolean | true | Enable smooth CSS transitions when the stencil snaps to position. |
Stencil
| Prop | Type | Default | Description |
|---|---|---|---|
stencil | Component | CropStencil | Stencil component. Pass CircleStencil for circular crop. |
stencilProps | Record<string, unknown> | {} | Extra props forwarded to the stencil component. |
Interaction
| Prop | Type | Default | Description |
|---|---|---|---|
readOnly | boolean | false | Disable all user interactions (view-only mode). |
HTML
| Prop | Type | Default | Description |
|---|---|---|---|
class | string | '' | Extra CSS class on the root element. |
style | string | '' | Inline styles on the root element. |
Bindable values
| Binding | Type | Description |
|---|---|---|
bind:coordinates | CropCoordinates | Two-way binding for the current crop coordinates (normalised, pixels, viewport). |
bind:transforms | TransformState | Two-way binding for transform state (rotation, flip, zoom, pan). |
Events
| Event | Type | Description |
|---|---|---|
onchange | (c: CropCoordinates) => void | Fires whenever the crop region changes. |
onready | () => void | Fires when the image has loaded and the cropper is interactive. |
onerror | (e: Error) => void | Fires when image loading fails. |
Snippets
Override default UI regions by passing named snippets:
| Snippet | Props | Description |
|---|---|---|
overlay | StencilProps | Custom overlay drawn on top of the stencil area. |
toolbar | CropperReturn | Custom toolbar with full access to the cropper instance. |
empty | — | Shown when no image source is provided. |
loading | — | Shown while the image is loading. |
error | Error | Shown when image loading fails. |
CropCoordinates type
Every coordinate callback and binding provides a CropCoordinates object with three
representations of the same crop region:
interface CropCoordinates {
/** Crop rect relative to original image (0-1 normalised) */
normalized: Rect;
/** Crop rect in original image pixels */
pixels: Rect;
/** Crop rect relative to the editor viewport */
viewport: Rect;
} Stencil types
Use the built-in CropStencil (rectangular) or CircleStencil (circular mask):
<script lang="ts">
import { Cropper, CircleStencil } from '@we-are-singular/svelte-chop-chop';
</script>
<Cropper src="/avatar.jpg" aspectRatio={1} stencil={CircleStencil} /> Note: CircleStencil automatically forces a 1:1 aspect ratio regardless of the aspectRatio prop.
Export
Bind this to get a reference to the cropper instance and call export():
<script lang="ts">
import { Cropper } from '@we-are-singular/svelte-chop-chop';
import type { ExportResult } from '@we-are-singular/svelte-chop-chop';
let cropper: Cropper;
async function save() {
const result: ExportResult = await cropper.export({
format: 'image/webp',
quality: 0.92,
maxWidth: 1200,
});
// result.blob — the exported Blob
// result.file — a File object (for FormData uploads)
// result.dataURL — base64 data URL string
// result.canvas — the HTMLCanvasElement used for rendering
// result.coordinates — CropCoordinates
// result.transforms — TransformState
// result.originalSize — { width, height }
const url = URL.createObjectURL(result.blob!);
const a = document.createElement('a');
a.href = url;
a.download = 'cropped.webp';
a.click();
}
</script>
<Cropper bind:this={cropper} src="/photo.jpg" />
<button onclick={save}>Download</button> ExportResult type
interface ExportResult {
canvas?: HTMLCanvasElement;
blob?: Blob;
file?: File;
dataURL?: string;
coordinates: CropCoordinates;
transforms: TransformState;
originalSize: Size;
} Presets
Spread a preset to preconfigure the Cropper for common use cases:
<script lang="ts">
import { Cropper } from '@we-are-singular/svelte-chop-chop';
import { profilePicture } from '@we-are-singular/svelte-chop-chop/presets';
</script>
<Cropper src="/photo.jpg" {...profilePicture} /> Available presets: profilePicture (1:1, 512px), coverPhoto (16:9, min 1200px), productImage (1:1, PNG).
Keyboard shortcuts
When the cropper container is focused:
| Key | Action |
|---|---|
Arrow keys | Move stencil 1px (10px with Shift) |
+ / - | Zoom in / out |
0 | Reset zoom (fit to view) |
Escape | Reset crop to fit image |
Custom stencil
See the Custom Stencil guide for details on writing your own stencil component.