Skip to content
Kappa
Image Cropper
@dicehub/kappav0.4.2

Image Cropper

Crop local images with a movable, resizable selection. Keep a fixed ratio or resize freely, then preview and export in the browser.

Workspace imageSample illustration · 960 × 640 px
Loading image…

Local files stay in your browser. PNG export is limited to 512 × 512 px.

<script setup lang="ts">
import { ref } from "vue";
import { ImageCropper, type ImageCropperApi } from "@dicehub/kappa/components/image-cropper";
import { Button } from "@dicehub/kappa/components/button";

const cropper = ref<ImageCropperApi>();
const source = ref<string | File>("/images/demos/cropper-field.svg");
const ready = ref(false);
const error = ref("");

async function saveCrop() {
  try {
    const blob = await cropper.value!.exportBlob({
      type: "image/png", maxSize: { width: 512, height: 512 },
    });
    // Send this Blob to your application's storage service.
    console.log(blob.type, blob.size);
  } catch (cause) {
    error.value = cause instanceof Error ? cause.message : "Export failed.";
  }
}
</script>

<template>
  <ImageCropper ref="cropper" :src="source" :aspect-ratio="1"
    @status-change="ready = $event === 'ready'"
    @error="error = $event.error.message" />
  <Button :disabled="!ready" @click="saveCrop">Save crop</Button>
  <p v-if="error" role="alert">{{ error }}</p>
</template>

Installation

import { ImageCropper } from "@dicehub/kappa";
// Or: "@dicehub/kappa/components/image-cropper"

Import @dicehub/kappa/styles/theme-kappa.css once in your application. Component imports include only the required component styles.

Composition

Kappa composes Ark UI Image Cropper with Kappa Slider and Button. Ark owns selection limits, resize gestures, focus semantics, and keyboard controls. Kappa keeps the image fixed and adds image loading, a live preview, lifecycle cleanup, and a smaller application API.

The crop frame stays inside the image and can move without moving the source. Eight handles resize it. Numeric ratios preserve their proportions; aspect-ratio="free" allows independent width and height. The viewport follows the source ratio so that wide and tall images keep their proportions. Kappa calculates rectangular exports from fractional viewport coordinates. The preview uses the same crop. Use Avatar or application CSS to display the result as a circle.

Compose File Upload outside the cropper for file choice, type checks, and file-size limits. The demo allows images up to 10 MB. The component does not select files, call an upload service, or depend on an application store.

Examples

Cover images and aspect ratios

Use a fixed ratio for each destination. A ratio change resets the crop and zoom. The source stays fixed inside the viewport.

Cover imageSample illustration · 960 × 640 px
Loading image…

Local files stay in your browser. PNG export is limited to 512 × 512 px.

<ImageCropper :src="imageFile" :aspect-ratio="16 / 9" :max-zoom="3" />

Custom crop

Use free mode when the output has no fixed ratio. Drag the crop area to move it. Drag any edge or corner to resize width and height independently.

Custom cropSample illustration · 960 × 640 px
Loading image…

Local files stay in your browser. PNG export is limited to 512 × 512 px.

<ImageCropper :src="imageFile" aspect-ratio="free" />

Read only, disabled, and empty

Read-only content remains focusable and can be exported. Disabled content blocks editing and export. Clear the source to show the empty state.

Interaction statesSample illustration · 960 × 640 px
Loading image…

Local files stay in your browser. PNG export is limited to 512 × 512 px.

<ImageCropper :src="imageFile" read-only />
<ImageCropper :src="imageFile" disabled />
<ImageCropper :src="null" />

Accessibility

Tab reaches the crop selection, zoom slider, and reset button. On the selection, arrow keys move the crop; Alt plus an arrow resizes its bottom or right edge. Shift increases the step to 10 pixels and Control or Command increases it to 50 pixels. Plus and minus zoom. The zoom slider uses Ark UI keyboard controls, including Home, End, and Page Up or Page Down.

The selection has a visible focus ring and reports its original-image coordinates to assistive tools. Pointer and touch input can move or resize the crop. The viewport captures the wheel for zoom. Read-only mode keeps the selection focusable. Disabled mode removes the editing controls from the tab order. Reduced-motion mode removes grid transitions.

Set labels to localize the visible labels and instructions. Native attributes, ARIA attributes, and listeners reach the outer root. Use labels.region and labels.selection to name the interactive regions.

API reference

src?: string | Blob | null accepts a URL, File, or Blob; null clears the image. aspectRatio?: number | "free" defaults to 1. Positive numbers lock the crop ratio; free enables independent edge and corner resizing. Invalid ratios use 1. maxZoom defaults to 5 and is clamped from 1 to 20. showPreview defaults to true. disabled and readOnly default to false. crossOrigin defaults to anonymous and also accepts use-credentials.

labels accepts any of: region, selection, instructions, zoom, reset, preview, empty, loading, and error. The root exposes data-state="empty | loading | ready | error", data-disabled, and data-readonly.

change reports { x, y, width, height, zoom, naturalWidth, naturalHeight }. Coordinates refer to the original image pixels and can be fractional. load reports the decoded width and height; the editor then measures the crop. statusChange reports source status. error reports { phase: "load" | "export", error: Error }.

The template ref implements ImageCropperApi: reset() restores the centered crop at 100%; setZoom(number) respects limits; getCrop() returns the crop or null; and exportBlob(options?) returns Promise<Blob>. Disabled and read-only states block reset and zoom. Read-only export remains available.

Export options are type (image/png, image/jpeg, or image/webp), quality (0–1; default 0.92), and maxSize (width and height; default 2048 × 2048). Output is scaled down proportionally, with no upscale. Each dimension must be from 1 to 8192 pixels. The browser may fall back to PNG for an unsupported encoder; check blob.type.

Public types include ImageCropperProps, ImageCropperSource, ImageCropperStatus, ImageCropperCrop, ImageCropperApi, ImageCropperLabels, ImageCropperEmits, ImageCropperErrorDetails, and ImageCropperExportOptions. The root and granular imports expose the same API. The package export wildcard covers the component subpath.

Loading, disposal, and export

The source loads in the browser after mount. A source change clears the previous crop and resets its position and zoom. Superseded load callbacks are ignored. URLs made from Blob sources are revoked on replacement or unmount; URLs supplied by the application remain application-owned.

Export rejects while the editor is unavailable, if a canvas cannot encode the result, or if the source changes during export. A source replacement or unmount rejects an active export with AbortError. Catch export errors in the application. If you make a URL with URL.createObjectURL for the returned Blob, revoke it when your preview or download is no longer needed.

Remote image hosts must allow cross-origin image access. A denied CORS request shows the error state. This version produces rectangular raster exports; rotation, flip, and animated output are not part of the Kappa API.