A couple of months ago, I started a project with other peers to create a website that helps Korean learners, especially young kids, practice Korean through interactive games.
This project was initiated by a teacher currently working at a Korean school in the US. It aims to help students easily learn Korean by repeatedly practicing the consonants, vowels, and their combinations through various games.
The main target audience is young kids, so the game had to be simple to play while including many interactive elements to keep them engaged. One of the games, a word-matching game, requires users to find matching words and drag the answer to the correct spot.
The drag effect I implemented this time was simpler than the one I created for my portfolio website (which had a Trello-style drag-and-drop feature).
However, this new drag effect needed to work on both pointer and touch devices. Although the drag event provides some helpful features, like dragImage and dataTransfer, I needed to explore the differences between drag events and touch events to ensure compatibility across devices.
Here are some key differences between touch events and drag events:
Triggering Timing and Sequence
Touch Events
- Touch events are triggered when a user touches the screen.
- The types of touch events include
touchstart,touchmove, andtouchend. - These events are triggered immediately upon contact with the screen, giving them a faster response time.
Drag Events
- Drag events are mainly used for handling drag-and-drop actions with a mouse or pointer device.
- The types of drag events include
dragstart,drag,dragend. - Drag events require the element to be draggable by setting
draggable="true"in HTML, and they won’t start unless the element is set to be draggable. - Drag events are typically suited for desktop interactions and tend to be slower compared to mouse events or touch events, especially
dragevent might feel less responsive thanmousemoveortouchmovebecause they are controlled by the browser’s native drag-and-drop event system.
Key Features and Differences
Touch Events
- Touch events can detect multiple touch points
- Touch events are lightweight and optimized for mobile, where response speed is crucial.
- Used in several gestures, such as drag-and-drop, swipes, taps, and pinches.
- There aren’t many differences between handling events in vanilla JavaScript and React.
Drag Events
- Drag events require elements to be explicitly set as draggable.
- Drag events support data transfer, which is useful when transferring data, such as files or text, between applications of elements.
- Drag events are single-point and cannot track multiple gestures.
- Since React uses virtual DOM, direct DOM manipulation is discouraged, and the drop event in React should be handled differently, especially when DOM needs to be updated.
When transferring data like files or text, using the drag event is convenient in many ways. However, when implementing an action to drag a specific element and move it to another position—especially if you want consistent behavior across multiple devices—I found that using both drag and touch events can make things significantly more complex and challenging to manage. This led me to explore simpler and more efficient methods to handle drag interactions across different devices.
So, I came up with a method that combines move events with touch events. Like the drag event, the move event is also a single-point event, but it shares many behavioral characteristics with touch events. By using these two events together, I could apply the same logic across different devices.
Here’s a quick summary of the advantages of using these two events together:
Direct Control Over Movement
Mouse and touch events both provide direct access to the element’s coordinates(clientX and clientY ). This allows you to handle the element’s position directly, giving full control over the dragging behavior.
Easier to Implement and Maintain
With mouse and touch events, you can unify the logic by using the same handlers(e.g., mousedown/ mousemove for mouse and touchstart/ touchmove for touch). This creates simpler, more maintainable code and reduces redundancy.
Consistent Behavior Across Devices
Mouse events work seamlessly on desktop, while touch events handle mobile more effectively. Combining these makes it easier to ensure consistent, smooth interactions on both types of devices without additional fallback code.
When implementing a drag-and-drop effect using mouse and touch events, I listed out the key functionalities needed.
First, when the initial event is triggered on the target element, the pointer or touch point position must be saved to move the element along with the pointer or touch point. Then, tracking the pointer's movement and updating the element’s position is essential.
Finally, depending on the event outcome, the DOM or styling should be updated when the pointer reaches the target drop area.
To summarize:
- Save the pointer or touch point position within the drag element when the initial event (
mousedownortouchstart) is triggered. - Update the drag element’s position during the movement using
mousemoveortouchmoveevents. - Pre-store the drop element's location and, when the pointer or touch point event (
mouseuportouchend) occurs within this area, update the DOM or styling as needed upon drop.
Drag Section
My approach to creating the dragging effect involves attaching mousedown and touchstart event listeners to the draggable elements. When these events are triggered, the handler stores the pointer's screen position, the offset position of the pointer within the draggable element, and the dragging item’s information.
I also created a custom hook, useDragDrop, to store drag and drop items and their positions. In this hook, once a dragItem is assigned, mousemove and touchmove listeners are attached to track the pointer’s position, while mouseup and touchend listeners check the dropping position. As the pointer moves, the hook updates the pointer’s position, allowing the dragging element to follow the pointer accurately.
To show a grabbing motion when the drag starts, I applied grab and grabbing styles by checking that the dragItem ID matched the current item’s ID.
Drop Section
Using the useDragDrop hook allowed me to update the position of the dragging item smoothly.
One issue I encountered, however, was implementing a hover effect when the drag item hovers over the drop item. When I added the Tailwind class hover:bg-lighter to the drop item (equivalent to &:hover { background-color: var(--bg-lighter); }), the effect didn’t actually work as expected.
The reason for the issue was that since the dragging item is right under the pointer, the actual element that could trigger mouseover effect was the drag item itself. So, I tweaked the logic little bit by checking if the Id of dropItem from the useDragDrop hook is the same as the current item’s Id like below.
This condition enabled the hover effect to activate correctly when the pointer entered the dropItem area.
The final step was to verify whether the dragItem was dropped in the correct area when the mouseup or touchend event was triggered. If it was, the item moved to the drop zone; if not, it returned to its original position using the handleDrop function from the useDragDrop hook.
In summary, implementing drag-and-drop functionality across both mouse and touch devices required a custom approach using the useDragDrop hook to handle events and positions efficiently. By combining mousemove/touchmove and mouseup/touchend events, I was able to create a smooth, cross-device drag-and-drop experience. This process highlighted the importance of tailoring interactions for different device types, and in the future, additional features like snapping to the drop area or adding transition effects could further improve the user experience.