ImageEditor

The all-in-one ImageEditor component provides a full-featured editing toolbar driven by a plugin system. Crop, filter, tune, resize, frame and watermark — all in one component.

The crop stencil (overlay and handles) is shown only when the crop tab is active. When you switch to filters, finetune, frame, or watermark, the stencil is hidden so you can focus on the current tool.

Import

import { ImageEditor } from '@we-are-singular/svelte-chop-chop';

Props

PropTypeDefaultDescription
srcImageSourceImage URL, data URL, File , Blob , or HTMLImageElement .
pluginsChopPlugin[][]Plugin instances that add toolbar tabs and functionality.
aspectRationumber | { min?: number; max?: number } | nullnullInitial crop aspect ratio.
initialCropScalenumber0.8Initial crop as fraction of image (0–1). 0.8 = 80% centered. Applied when changing aspect ratio or stencil too.
classstring''Extra CSS class on the root element.

Events

EventTypeDescription
onexport(blob: Blob) => voidFires when the user presses the export/save button. Receives the exported Blob .
oncancel() => voidFires when the user presses cancel/close.

Minimal editor (crop + rotate only)

Use ImageEditor without plugins for just crop and rotate:

Crop and rotate only (no plugins)

No image loaded
<ImageEditor src="/photo.jpg" style="height: 320px;" />

Full example with all plugins

ImageEditor with all plugins

No image loaded
<script lang="ts">
  import { ImageEditor } from '@we-are-singular/svelte-chop-chop';
  import { pluginFilters, pluginFinetune, pluginFrame, pluginWatermark, pluginResize } from '@we-are-singular/svelte-chop-chop';
  import '@we-are-singular/svelte-chop-chop/themes/default';

  function handleExport(result) {
    if (result.blob) {
      const url = URL.createObjectURL(result.blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = 'edited.jpg';
      link.click();
      URL.revokeObjectURL(url);
    }
  }
</script>

<ImageEditor
  src="/photo.jpg"
  plugins={[pluginFilters(), pluginFinetune(), pluginFrame(), pluginWatermark(), pluginResize()]}
  onexport={handleExport}
/>

Upload to server example

<script lang="ts">
  import { ImageEditor } from '@we-are-singular/svelte-chop-chop';
  import { pluginFilters } from '@we-are-singular/svelte-chop-chop/plugins/filters';

  async function handleExport(blob: Blob) {
    const formData = new FormData();
    formData.append('image', blob, 'photo.jpg');
    await fetch('/api/upload', { method: 'POST', body: formData });
  }
</script>

<ImageEditor
  src="/photo.jpg"
  plugins={[pluginFilters()]}
  onexport={handleExport}
/>

Keyboard shortcuts

The editor accepts keyboard input when focused:

KeyAction
RRotate 90° clockwise
Shift+RRotate 90° counter-clockwise
HFlip horizontal
VFlip vertical
Ctrl+ZUndo
Ctrl+Shift+ZRedo
Arrow keysMove crop 1px (10px with Shift)
+ / -Zoom in / out
0Reset zoom (fit to view)
EscapeCancel / close

Headless composable

For full UI control, use createImageEditor from the headless export. It returns a reactive state object with all actions:

import { createImageEditor } from '@we-are-singular/svelte-chop-chop/headless';
import { pluginFilters } from '@we-are-singular/svelte-chop-chop/plugins/filters';
import { pluginFinetune } from '@we-are-singular/svelte-chop-chop/plugins/finetune';

const editor = createImageEditor({
  plugins: [pluginFilters(), pluginFinetune()],
});

// Load an image
await editor.loadImage('/photo.jpg');

// Apply a filter
editor.applyFilter('clarendon');

// Adjust finetune
editor.setFinetune('brightness', 20);
editor.setFinetune('contrast', 10);

// Rotate and flip
editor.rotate(90);
editor.flipX();

// Undo / redo
editor.undo();

// Export
const result = await editor.export({
  format: 'image/webp',
  quality: 0.9,
  maxWidth: 1920,
});

// result.blob, result.file, result.dataURL, result.canvas
// result.coordinates, result.transforms, result.originalSize

Export options

Export renders at full resolution using the original image pixels. The viewport size does not limit output — a large image displayed small will export at its cropped region's actual dimensions. Use maxWidth / maxHeight to downscale if needed.

OptionTypeDefaultDescription
format'image/jpeg' | 'image/png' | 'image/webp''image/png'MIME type for the output image.
qualitynumber0.92Compression quality 0–1 (JPEG/WebP only).
maxWidthnumberMaximum output width. Downscales proportionally if exceeded.
maxHeightnumberMaximum output height. Downscales proportionally if exceeded.
shape'rect' | 'circle''rect'Crop shape. 'circle' applies a circular mask with transparent corners. Automatically uses PNG if JPEG was selected (JPEG doesn't support transparency).
postProcess(ctx, canvas) => void | PromiseHook to draw on the canvas after rendering but before encoding (e.g. custom watermark).

ExportResult type

interface ExportResult {
  canvas?: HTMLCanvasElement;
  blob?: Blob;
  file?: File;
  dataURL?: string;
  coordinates: CropCoordinates;
  transforms: TransformState;
  originalSize: { width: number; height: number };
  filters?: FilterState;  // Filter state applied at export
}