# How to Create a Cropper Component in Vue Using TypeScript and vue-advanced-cropper

Using a pre-defined cropper such as Vue-advanced-cropper can save you a lot of time, but using it properly as a reusable component is not always easy to implement. In this tutorial, you will learn how to create a cropper component in Vue using TypeScript and the vue-advanced-cropper library.

## **Getting Started**

First, you need to install the [Vue-advanced-cropper](https://advanced-cropper.github.io/vue-advanced-cropper/) library. You can do this by running the following command in your terminal:

```bash
npm install vue-advanced-cropper
```

Once the library is installed, is time to create our reusable component. You can do this by creating a new file called `BaseCropper.vue`

## The code

The following code shows the basic structure of the `BaseCropper.vue` component:

```xml
<script lang="ts" setup>
import { Cropper } from 'vue-advanced-cropper'
import 'vue-advanced-cropper/dist/style.css'
import { ref, watch } from 'vue'
defineProps({
  imageSource: {
    type: String,
    required: true,
  },
  imageSize: {
    type: Object,
  },
})
const imageRef = ref('parentImageRef')
const emit = defineEmits(['onImageChange', 'onCrop', 'onCancel'])
watch(imageRef, () => {
  emit('onImageChange', imageRef.value)
})
</script>

<template>
  <div>
    <Cropper
      ref="imageRef"
      :src="imageSource"
      :stencil-size="imageSize"
      :stencil-props="{
        handlers: {},
        movable: false,
        resizable: false,
      }"
      image-restriction="stencil"
    />
    <hr class="solid" >
    <div>
      <button @click="$emit('onCancel')">Cancel</button>
      <button @click="$emit('onCrop')">Crop image</button>
    </div>
  </div>
</template>

<style>
.cropper {
  min-height: 300px;
  width: 100%;
}
hr.solid {
  border-top: 3px solid #bbb;
}
</style>
```

The template for the `Cropper` component is simple. It simply renders the `Cropper` component with the imageSource and imageSize props. It also renders a hr element and two buttons. The first button is used to cancel the crop, and the second button is used to crop the image.

## Piece by piece

Now will let's explain the complete code piece by piece

```xml
<script lang="ts" setup>
import { Cropper } from 'vue-advanced-cropper'
import 'vue-advanced-cropper/dist/style.css'
import { ref, watch } from 'vue'

// Define the props
defineProps({
  imageSource: {
    type: String,
    required: true,
  },
  imageSize: {
    type: Object,
  },
})

// Create a ref to the image
const imageRef = ref('parentImageRef')

// Define the emits
const emit = defineEmits(['onImageChange', 'onCrop', 'onCancel'])

// Watch the imageRef and emit the onImageChange event when it changes
watch(imageRef, () => {
  emit('onImageChange', imageRef.value)
})
</script>
```

The first part of the code imports the `Cropper` component from the `vue-advanced-cropper` library. It also imports the CSS styles for the `Cropper` component. Then, it defines the props for the `Cropper` component. There are just two props that I consider necessary in my component but there are a lot of possible props, you can explore the [library API](https://advanced-cropper.github.io/vue-advanced-cropper/components/cropper.html) to define those you could add.

The `imageSource` prop is required and is the URL of the image that you want to crop. The `imageSize` prop is an object that specifies the width and height of the image.

Next, the code creates a ref to the image. This ref will be used to access the image in the template. Then, let's define the emits for the `Cropper` component.

The `onImageChange` event is emitted when the image changes (This will be used by the parent component to update its ref). The `onCrop` event is emitted when the crop is complete, and the `onCancel` event is emitted when the user cancels the crop.

Finally, the code watches the image and emits the `onImageChange` event when it changes. This ensures that the image is always up-to-date.

```xml
<template>
  <div>
    <Cropper
      ref="imageRef"
      :src="imageSource"
      :stencil-size="imageSize"
      :stencil-props="{
        handlers: {},
        movable: false,
        resizable: false,
      }"
      image-restriction="stencil"
    />
    <hr class="solid" >
    <div>
      <button @click="$emit('onCancel')">Cancel</button>
      <button @click="$emit('onCrop')">Crop image</button>
    </div>
  </div>
</template>
```

```xml
<style>
.cropper {
  min-height: 300px;
  width: 100%;
}
hr.solid {
  border-top: 3px solid #bbb;
}
</style>
```

The CSS styles for the `Cropper` component are very simple. They simply set the min-height and width of the `Cropper` component to 300px and 100%, respectively.

## Using the component

Once the component is created, we can use it.

In this example, I'm using it in a custom dialog component after a file was selected

```xml
<BaseDialog v-model="coverDialog">
    <ImageCropper
        :image-source="coverPicked"
        :image-size="{
            width: 500,
            height: 200,
        }"
        @on-crop="cropCoverImage"
        @on-cancel="closeCoverDialog"
        @on-image-change="updateCoverRef"
    />
</BaseDialog>
```

And the result is:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1689889002834/05db6ec3-88f3-4050-b8a3-67c29f71fe5f.png align="center")

## Conclusion

This is a basic example of how to create a Cropper Vue component using TypeScript and Vue-advanced-cropper. You can use this code as a starting point to create your own Cropper component.
