← Back toDrag and drop in React

Crop a portion of an image

Written byPhuoc Nguyen
Created
13 Nov, 2023
Last updated
15 Nov, 2023
Tags
React image cropper
Cropping an image is a simple yet powerful technique that can greatly improve the visual appeal and composition of your photographs. It involves removing unwanted or unnecessary parts of an image, which helps focus the viewer's attention on the main subject.
One of the key benefits of cropping images is that it allows you to remove distracting elements from a photo. For example, if you've taken a beautiful landscape photograph but there's a trash can in the corner of the frame, cropping the image can help you remove this distraction and improve the overall composition.
Cropping also enables you to change the aspect ratio of an image, which can be useful if you want to create prints or digital images in specific sizes. By cropping an image, you can ensure it fits perfectly into your desired format without having to stretch or distort the original picture.
Moreover, cropping an image can help highlight certain details or features that might otherwise be lost in a cluttered scene. By zooming in on a particular area, you can bring out textures, shapes, and colors that may not have been visible before.
In summary, cropping images is an essential tool for any photographer who wants to enhance their photos' visual impact and composition. Whether you're removing distractions, changing aspect ratios, or highlighting details, cropping is a simple yet effective way to take your photography skills to the next level.
In this post, we'll explore how to crop a portion of an image using React.

Making the selection draggable

In our previous post, we learned how to build an image cropper. However, we only positioned the cropping area at the top-left corner of the image. This isn't always the best approach, especially in a more advanced image editor.
In this post, we're going to show you how to create a cropping area when needed. This can be done by clicking a button in the toolbar or, as we'll be demonstrating, by clicking on the image and dragging the mouse to select the desired area. Once the area is selected, users can then drag or resize it as needed.
To accomplish this, we'll be using the `useClickToSelect` hook that we previously created. If you need a refresher, here's a code snippet to help jog your memory.
ts
const [clickToSelectRef, dx, dy, startX, startY, selection] = useClickToSelect();
The hook we're using returns an array of six items. The first item is a reference to the target element that allows for click-and-drag functionality. To make this work, we'll attach the reference to the container using the `ref` attribute.
tsx
<div className="container" ref={clickToSelectRef}>
...
</div>
The next items can help generate a preview of a selected portion. You can use `dx` and `dy` to set the width and height of the selection, while `startX` and `startY` can indicate the position of the selection.
tsx
{
selection === Selection.Dragging && (
<div
className="selection"
style={{
transform: `translate(${startX}px, ${startY}px)`,
width: `${dx}px`,
height: `${dy}px`,
}}
/>
)
}
It's important to note that the selection only appears after users release the mouse following a click-and-drag action. To figure this out, simply check if the `selection` state is `Selection.Dragging`.
Additionally, we're able to reuse the `useDraggable` hook, which allows any element to become draggable. The hook returns an array of three items.
ts
const [draggableRef, dragX, dragY] = useDraggable();
The first item in the array sets the reference of the target element using the `ref` attribute. Meanwhile, the last two items, `dragX` and `dragY`, position the target element and are updated in real-time as users move it around.
Let's take a look at some sample code to see how we can use these items to modify an existing element:
tsx
<div
ref={draggableRef}
className="draggable"
style={{
transform: `translate(${dragX}px, ${dragY}px)`,
}}
/>
Now that you have a basic understanding of how two custom hooks work, let's dive into how to turn a selected portion into a draggable cropping area.
The cropping area will only show up after users release the mouse. To make that happen, we need to check if the user has let go of the mouse by comparing the `selection` state to the `Selection.Selected` value. Once the values match, we can display the cropping area.
tsx
const [..., selection] = useClickToSelect();

// Render
{
selection === Selection.Selected && (
<div
ref={draggableRef}
className="draggable"
style={{
transform: `translate(${dragX}px, ${dragY}px)`,
width: `${dx}px`,
height: `${dy}px`,
}}
/>
)
}

Adjusting the cropping area position

To make sure that the cropping area is positioned correctly on the image, we need to update the `useDraggable()` hook slightly. This hook enables us to make an element draggable by updating its position based on user input. In our case, we want to update the position of the cropping area based on where users click and drag on the image.
To achieve this, we will add the `setOffset` function to the returned value of `useDraggable()`.
ts
const [..., setOffset] = useDraggable();
Next, let's keep an eye on the `startX` and `startY` values that come back from the `useClickToSelect()` hook. These values tell us where the selected part of the image starts, and we need them to know where to put the cropping area.
We'll use a `useEffect()` hook to keep tabs on changes to `startX` and `startY`, and then we'll use the `setOffset()` function that `useDraggable()` gives us to update the position of the cropping area. This way, as users move their selection around on the image, the cropping area moves right along with them.
ts
React.useEffect(() => {
setOffset({
dx: startX,
dy: startY,
});
}, [startX, startY]);
By monitoring specific values and updating our state accordingly, we can create a seamless user experience that allows for precise control over image cropping. This results in both the selection and the cropping area being synced in terms of position and dimension.
Check out the demo below! Simply click on the container and drag your mouse around. As you move the mouse, the selection is generated. When you release the mouse, the cropping area is generated in the same position and size as the selection.
You can then easily drag the cropping area within the container to adjust the final area as needed.

Upgrading the image cropper

By following the techniques outlined in the previous sections and the steps for creating an image cropper, we can create a fully-functional image cropper with React.
Go ahead and play around with the demo below to see the results in action.

Conclusion

Creating a custom image cropper in React is actually easier than you might think. By using the `useClickToSelect` and `useDraggable` hooks, you can give users a seamless experience that allows for precise control over image cropping.
In this post, we covered how to turn a selected portion of an image into a draggable cropping area, adjust its dimensions, and position it correctly on the image. With these techniques in mind, you can create your own custom image cropper with ease.
Just remember to keep the user experience in mind during your design process. Make sure that users understand how to use your image cropper so they can feel confident in their ability to crop images precisely.
If you found this post helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!

Questions? 🙋

Do you have any questions about front-end development? If so, feel free to create a new issue on GitHub using the button below. I'm happy to help with any topic you'd like to learn more about, even beyond what's covered in this post.
While I have a long list of upcoming topics, I'm always eager to prioritize your questions and ideas for future content. Let's learn and grow together! Sharing knowledge is the best way to elevate ourselves 🥷.
Ask me questions

Recent posts ⚡

Newsletter 🔔

If you're into front-end technologies and you want to see more of the content I'm creating, then you might want to consider subscribing to my newsletter.
By subscribing, you'll be the first to know about new articles, products, and exclusive promotions.
Don't worry, I won't spam you. And if you ever change your mind, you can unsubscribe at any time.
Phước Nguyễn