An SSR ready Svelte wrapper for CropperJS. Please refer to the original CropperJS documentation for detailed usage instructions.
npm install -D @eslym/svelte-cropperjs
yarn add -D @eslym/svelte-cropperjs
bun add -d @eslym/svelte-cropperjs
<script lang="ts">
import type { CropperSelection } from '@cropper/elements';
import * as Cropper from '@eslym/svelte-cropperjs';
let cropper: CropperSelection = $state(null!);
async function crop() {
const canvas = await cropper.$toCanvas({ width: 256, height: 256 });
const blob = await new Promise<Blob>((resolve) =>
canvas.toBlob((b) => resolve(b!), 'image/png')
);
const u = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = u;
a.download = 'cropped-image.png';
a.click();
URL.revokeObjectURL(u);
}
</script>
<div class="grid grid-cols-[1fr_auto]">
<Cropper.Canvas background class="h-dvh w-full">
<Cropper.Image
src="/example.png"
alt="Example Image"
rotatable
scalable
skewable
translatable
/>
<Cropper.Shade />
<Cropper.Handle action="move" plain />
<Cropper.Selection
id="selection"
bind:element={cropper}
aspect-ratio={1}
initial-aspect-ratio={1}
initial-coverage={1}
movable
resizable
>
<Cropper.Grid bordered covered />
<Cropper.Crosshair centered themeColor="#0000FF80" />
<Cropper.Handle action="move" plain />
<Cropper.Handle action="n-resize" />
<Cropper.Handle action="e-resize" />
<Cropper.Handle action="s-resize" />
<Cropper.Handle action="w-resize" />
<Cropper.Handle action="ne-resize" />
<Cropper.Handle action="nw-resize" />
<Cropper.Handle action="se-resize" />
<Cropper.Handle action="sw-resize" />
</Cropper.Selection>
</Cropper.Canvas>
<div class="flex w-80 flex-col gap-2 p-4">
<h2 class="mb-4 text-lg font-bold">Svelte CropperJS</h2>
<Cropper.Viewer selection="#selection" class="border" />
<Cropper.Viewer selection="#selection" class="rounded-full border" />
<button
onclick={crop}
class="col-span-2 m-4 rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700"
>
Crop & Download
</button>
</div>
</div>