Getting Started

Install svelte-chop-chop and add image cropping to your Svelte 5 app in minutes.

Installation

npm install @we-are-singular/svelte-chop-chop

Peer dependencies

Only Svelte 5 is required as a peer dependency:

peerDependencies:
  svelte: "^5.0.0"

Basic cropper

Import the Cropper component and pass it an image source. Use the toolbar snippet to add an export button. Export uses full resolution (original image pixels), so large images export at their cropped region's actual dimensions.

Basic Cropper

No image loaded
<script lang="ts">
  import { Cropper } from '@we-are-singular/svelte-chop-chop';
  import '@we-are-singular/svelte-chop-chop/themes/default';
</script>

{#snippet cropToolbar(cropper)}
  <button onclick={async () => {
    const result = await cropper.export({ format: 'image/webp', quality: 0.9 });
    if (result.blob) {
      const url = URL.createObjectURL(result.blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = 'cropped.webp';
      a.click();
    }
  }}>Crop</button>
{/snippet}

<Cropper src="/photo.jpg" aspectRatio={1} toolbar={cropToolbar} />

Full image editor

The ImageEditor component bundles crop, filters, finetune, rotate, resize, frame and watermark panels:

Full ImageEditor with all plugins

No image loaded
<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';
</script>

<ImageEditor
  src="/photo.jpg"
  plugins={[pluginFilters(), pluginFinetune(), pluginFrame(), pluginWatermark(), pluginResize()]}
  onexport={(result) => console.log('exported', result.blob)}
/>

Headless composable

Need full UI control? Use createCropper from the headless export. Bind the container and canvas via $effect :

<script lang="ts">
  import { createCropper } from '@we-are-singular/svelte-chop-chop/headless';

  const cropper = createCropper({
    src: 'https://example.com/photo.jpg',
    aspectRatio: 16 / 9,
  });

  let containerEl: HTMLElement | undefined;
  let canvasEl: HTMLCanvasElement | undefined;

  $effect(() => {
    if (containerEl) cropper.bindContainer(containerEl);
    if (canvasEl) cropper.bindCanvas(canvasEl);
    return () => cropper.destroy();
  });
</script>

<div bind:this={containerEl} class="my-container" style="height: 300px;">
  <canvas bind:this={canvasEl}></canvas>
  <!-- Render your own stencil using cropper.stencilProps -->
</div>

See Cropper and Custom Stencil for details.

CSS themes

Three themes are included. Import exactly one:

import '@we-are-singular/svelte-chop-chop/themes/default'; // recommended
import '@we-are-singular/svelte-chop-chop/themes/dark';
import '@we-are-singular/svelte-chop-chop/themes/minimal';

Next steps