Library / SDK
zhanziyang/vue-croppa avatar
zhanziyang/vue-croppa

vue-croppa: an image cropper split across a Vue 2 line and a Vue 3 rewrite

A simple straightforward customizable mobile-friendly image cropper for Vue.

955 stars123 forksVueISC

At a glance

What is it?
vue-croppa is an ISC licensed cropper component for Vue that now ships as two parallel lines: v1 for Vue 2 applications, unchanged and still documented, and a Vue 3 and TypeScript rewrite published as v2. The interesting decisions are how the two lines coexist and how output sizing changed between them.
Who is it for?
vue-croppa suits a Vue application that needs a drag, zoom and rotate cropper with a blob or data URL output and a mobile friendly touch interface, and it is the wrong tool for a team that wants a single API across Vue versions or needs server side cropping of large images.
Can I use it commercially?
Yes. ISC is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 29 days ago.
What is it written in?
Mainly Vue, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One component, two supported Vue generations

vue-croppa describes itself as a simple, customizable, mobile-friendly image cropper for Vue, and the repository has been restructured to reflect that it now serves two very different audiences.

The readme's version status section is explicit. v2 supports Vue 3, and Vue 2 applications can stay on `vue-croppa@1`, with the latest 1.x release given as 1.3.8. There is a Vue 3 guide, an API page for v2 and a migration guide in `v2/MIGRATION.md`.

The release history shows how recent this restructuring is. v2.0.0 was published on 2026-09-23 and v2.1.0 on 2026-09-24, while the last v1 release before the rewrite, v1.3.7, dates from 2018-07-16. The last push to the default branch was on 2026-09-24.

So this is a project that spent years on the Vue 2 line and then, recently, published a Vue 3 and TypeScript rewrite. The repository layout makes the split physical rather than conceptual: there is a `v2/` directory holding the Vue 3 and TypeScript package source, a `src/` directory for the v1 component, a `docs/` directory holding the historical v1 build files and the compatibility harness, and a `site/` directory for the modern documentation.

The licence is ISC, with the text in `LICENSE.md`, and the npm package name is `vue-croppa`.

Output sizing was coupled in v1 and decoupled in v2

The single most consequential difference between the two lines is not the framework, it is how output resolution relates to what the user sees.

In v1 the visible cropper dimensions and the output resolution are coupled, and the readme states the relationship as a formula.

text
output width  = width × quality
output height = height × quality

So a 400 by 300 cropper at quality 0.9 produces an image scaled by that quality factor, and the numbers a developer sets on the component are not the numbers that end up in the file. That coupling is a common source of confusion, because the crop rectangle in the UI and the exported image have different pixel dimensions.

In v2 the visible canvas and the export use the same pixels at `quality` scale, and `autoSizing` is the option to follow a responsive container.

That is a behavioural change rather than a cosmetic one. Code written against v1 that assumed the output was scaled by quality will produce different pixel dimensions when moved to v2, and the readme's own sizing note exists precisely because people migrating will hit this.

So the choice between the two lines is not only a Vue version choice. If your backend stores images at a fixed size, or if you crop on the server afterwards, the change in output resolution has to be planned for rather than discovered.

The v2 component is a ref and a promised blob

The v2 usage example in the readme is short, and it shows the shape of the new API.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { Croppa } from 'vue-croppa'
import 'vue-croppa/style.css'

const cropper = ref<InstanceType<typeof Croppa> | null>(null)

async function save() {
  const blob = await cropper.value?.promisedBlob('image/png')
  // Upload or download the Blob.
}
</script>

<template>
  <Croppa ref="cropper" :width="320" :height="240" />
  <button @click="save">Save crop</button>
</template>

Three things changed against the v1 style. The import is a named import, `Croppa`, rather than a default export. The component is held through a template ref with an explicit instance type, `InstanceType<typeof Croppa>`, which is what makes the TypeScript typing work in a script setup block. And the output call is `promisedBlob('image/png')`, returning a Blob you upload or download yourself.

The readme also points to a live Vue 3 preview that uses the real v2 component, so you can check behaviour before wiring it into an application.

For v1 the shape is the Vue 2 plugin style, with `Vue.use(Croppa)` and a `v-model` that resolves to the component instance exposing movement, zoom, rotation, metadata and output methods. The smallest possible setup in v1 is a single element with a model binding.

Pinning the major version is now mandatory

Installation is a versioned install, and the readme is careful about how the two lines are selected.

bash
npm install vue-croppa@2

For Vue 2 applications the version is explicit as well.

bash
npm install vue-croppa@1

The reason the versions matter so much is a CDN trap, and the readme spells it out. For script tags you must pin v1 in CDN URLs, using `https://unpkg.com/vue-croppa@1/dist/vue-croppa.min.js` and `https://unpkg.com/vue-croppa@1/dist/vue-croppa.min.css`. Unversioned `unpkg.com/vue-croppa/dist/...` URLs now resolve to v2 and return 404.

That is a hard break for anyone copying an old script tag, and the failure mode is a 404 rather than a Vue 2 compatible bundle. The same applies to the stylesheet paths, since the v1 build is at `dist/vue-croppa.css` and the v2 import in the example is `vue-croppa/style.css`.

There is also a packaging detail worth noting. The repository's root package.json is still the v1 package, at version 1.3.8, with `main` pointing at `dist/vue-croppa.js` and a Rollup based build with `build:full`, `build:min` and `build:doc` scripts. The v2 package lives under `v2/`, and the readme says to run `npm run check` there for typecheck, unit tests and a library build.

The v1 line keeps a wide manipulation surface

The readme lists what v1 supports, and it is a longer list than the name suggests.

Drag to reposition the image, wheel and pinch zoom, rotation and horizontal or vertical flip, file chooser and drag and drop input, file type and file size validation, and local file EXIF orientation handling. Beyond that there is support for initial images, Blob and data URL output, canvas access and draw hooks, saving and restoring transform metadata, passive synchronized previews, responsive auto-sizing, and rounded or custom clipped output.

Two of those deserve more attention than the list gives them.

Passive synchronized previews means the component can mirror its state into another element, for instance a small preview next to the cropper that updates as the user drags, without the host application writing that synchronisation itself.

Canvas access and draw hooks, along with the watermark and draw hook example, mean you can draw onto the output canvas, which covers a case many croppers handle badly: overlaying a watermark or an annotation on the cropped result.

The v1 demo suite reflects the same breadth, with examples for basic crop, file input and drag and drop, move, zoom, rotate and flip, a zoom slider, responsive auto-sizing, blob and data URL output, upload and download recipes, metadata persistence, passive preview, watermark and draw hook, rounded output, custom loading, an image placeholder and an EXIF orientation hint.

The readme makes a point about how those demos are built: the documentation examples are part of the repository, there are no CodePen embeds in the new docs, and the pages execute the actual repository bundle and are exercised in Chromium by Playwright. The original `docs/simple-test.html` harness is also adapted to deterministic local assets and kept as an additional compatibility check.

Where vue-croppa is the wrong tool

The first limitation is obvious and worth stating plainly. This is a client side cropper. The cropping happens in the browser on the user's device, and the result is a Blob that your application then uploads. It does not crop on the server, so the full size original still travels over the wire unless you crop before upload, and a user with a 50 megapixel camera photo pays for that decode on their own machine.

The second is version fragmentation, which the project has handled as well as it can but not eliminated. Two component APIs exist, one per Vue generation, with different output sizing semantics, different import styles and different stylesheet paths. A team with both a Vue 2 and a Vue 3 application maintains two integrations.

The third is the maturity of v2 specifically. v2.0.0 and v2.1.0 were published within a day of each other in September 2026, and the v1 line's own last feature work predates that by years. So the Vue 3 path is new, and the Vue 2 path is stable but frozen in its current API. Choosing v2 means choosing the rewrite; choosing v1 means choosing the long stable line.

The fourth is the documentation split. The readme says the full v1 reference is organized by task rather than duplicated into the README, with separate pages for getting started, input and loading, manipulation and state, output and upload, customization, troubleshooting and the complete API reference. For v2 there is a guide and an API page, but the depth of the v1 documentation set is not there yet.

The licence is ISC, which is permissive and appropriate for a component like this, with no copyleft obligation on the application that embeds it.

Editorial conclusion

vue-croppa suits a Vue application that needs a drag, zoom and rotate cropper with a blob or data URL output and a mobile friendly touch interface, and it is the wrong tool for a team that wants a single API across Vue versions or needs server side cropping of large images. Before adopting v2, read the Vue 3 guide and the migration guide under `v2/MIGRATION.md`, because v2 was published on 2026-09-23 and its sizing model differs from v1, and if you are on Vue 2 pin `vue-croppa@1` explicitly, including in CDN URLs, since unversioned unpkg paths now resolve to v2 and return 404.

Frequently asked questions

Which Vue versions does vue-croppa support?

Version 2 supports Vue 3, and Vue 2 applications can stay on `vue-croppa@1`, whose latest 1.x release is 1.3.8. The v2 release line began with 2.0.0 on 2026-09-23 and 2.1.0 on 2026-09-24.

How do I install vue-croppa for Vue 3?

Run `npm install vue-croppa@2`, then import the named `Croppa` export together with `vue-croppa/style.css`. For Vue 2, install with `npm install vue-croppa@1` and use `Vue.use(Croppa)` with the `dist/vue-croppa.css` stylesheet.

How do I get the cropped image from the component?

In v2 you hold the component in a template ref and await `promisedBlob('image/png')`, then upload or download the Blob. In v1 the component instance is bound with `v-model` and exposes `promisedBlob('image/jpeg', 0.9)`.

What changed about output size in vue-croppa v2?

In v1 the visible cropper dimensions and the output resolution are coupled, with output width equal to width times quality. In v2 the visible canvas and the export use the same pixels at `quality` scale, and `autoSizing` follows a responsive container.

Why do my unpkg script tags return 404?

Unversioned `unpkg.com/vue-croppa/dist/...` URLs now resolve to v2 and return 404. The readme says to pin v1 in CDN URLs, for example `https://unpkg.com/vue-croppa@1/dist/vue-croppa.min.js` and the matching CSS file.

Official sources

  1. License: ISC
  2. Project website
  3. README
  4. Releases
  5. zhanziyang/vue-croppa on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/zhanziyang-vue-croppa.svg)](https://hysenlabs.com/projects/zhanziyang-vue-croppa)