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.
Import
import { ImageEditor } from '@we-are-singular/svelte-chop-chop';
Props
| Prop | Type | Default | Description |
|---|
src | ImageSource | — | Image URL, data URL, File, Blob, or HTMLImageElement. |
plugins | ChopPlugin[] | [] | Plugin instances that add toolbar tabs and functionality. |
aspectRatio | number | { min?: number; max?: number } | null | null | Initial crop aspect ratio. |
class | string | '' | Extra CSS class on the root element. |
Events
| Event | Type | Description |
|---|
onexport | (blob: Blob) => void | Fires when the user presses the export/save button. Receives the exported Blob. |
oncancel | () => void | Fires when the user presses cancel/close. |
Full example with all plugins
<script lang="ts">
import { ImageEditor } from '@we-are-singular/svelte-chop-chop';
import { pluginFilters } from '@we-are-singular/svelte-chop-chop/plugins/filters';
import { pluginFinetune } from '@we-are-singular/svelte-chop-chop/plugins/finetune';
import { pluginFrame } from '@we-are-singular/svelte-chop-chop/plugins/frame';
import { pluginWatermark } from '@we-are-singular/svelte-chop-chop/plugins/watermark';
import { pluginResize } from '@we-are-singular/svelte-chop-chop/plugins/resize';
import '@we-are-singular/svelte-chop-chop/themes/default';
function handleExport(blob: Blob) {
const url = URL.createObjectURL(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:
| Key | Action |
|---|
R | Rotate 90° clockwise |
Shift+R | Rotate 90° counter-clockwise |
H | Flip horizontal |
V | Flip vertical |
Ctrl+Z | Undo |
Ctrl+Shift+Z | Redo |
Arrow keys | Move crop 1px (10px with Shift) |
+ / - | Zoom in / out |
0 | Reset zoom (fit to view) |
Escape | Cancel / 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
| Option | Type | Default | Description |
|---|
format | 'image/jpeg' | 'image/png' | 'image/webp' | 'image/png' | MIME type for the output image. |
quality | number | 0.92 | Compression quality 0–1 (JPEG/WebP only). |
maxWidth | number | — | Maximum output width. Downscales proportionally if exceeded. |
maxHeight | number | — | Maximum 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 | Promise | — | Hook 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 };
}