Tips for confining the draggable div within its container

I've been working with React and TypeScript, and I recently added the W3School drag div example to my React app. However, I'm facing an issue where the draggable div is moving outside of the container. Can someone please guide me on how to confine the draggable div within the boundary without relying on any third-party libraries?

Here is a link to my sandbox demo

Here's my code:

import "./styles.css";
import React, { useRef } from "react";

export default function App() {
  const dragRef = useRef<HTMLDivElement>(null);
  let pos1 = 0,
    pos2 = 0,
    pos3 = 0,
    pos4 = 0;

  const drag = (event: any) => {
    const boundingBox = dragRef.current;

    if (boundingBox) {
      event = event || window.event;
      event.preventDefault();
      pos1 = pos3 - event.clientX;
      pos2 = pos4 - event.clientY;
      pos3 = event.clientX;
      pos4 = event.clientY;
      boundingBox.style.top = boundingBox.offsetTop - pos2 + "px";
      boundingBox.style.left = boundingBox.offsetLeft - pos1 + "px";
    }
  };

  const stop = () => {
    const boundingBox = dragRef.current;
    if (boundingBox) {
      boundingBox.onmouseup = null;
      boundingBox.onmousemove = null;
    }
  };

  const start = (event: any) => {
    const box = dragRef.current;
    if (box) {
      event = event || window.event;
      event.preventDefault();
      pos3 = event.clientX;
      pos4 = event.clientY;
      box.onmouseup = stop;
      box.onmousemove = drag;
    }
  };

  return (
    <div className="App">
      <div
        ref={dragRef}
        className="draggableDiv"
        onMouseDown={start}
        onMouseMove={drag}
        onMouseUp={stop}
      ></div>
    </div>
  );
}

And here's the external CSS file:

.App {
  font-family: sans-serif;
  height: 350px;
  width: 400px;
  background-color: rgb(132, 190, 241);
  position: relative;
}

.draggableDiv {
  position: absolute;
  height: 40px;
  width: 40px;
  background-color: red;
  cursor: grab;
}

Answer №1

To ensure the draggable area remains within a specified range, you can create an additional ref for the draggable area and validate the clientX and clientY coordinates against it.

  1. Set up a new ref and link it to the draggable area element.
const dragAreaRef = useRef<HTMLDivElement>(null);
...
...
  return (
    <div className="App" ref={dragAreaRef}>
      ...
    </div>
  );
  1. Update the drag function as shown below.
  const drag = (event: any) => {
    const boundingBox = dragRef.current;

    const {
      left,
      right,
      top,
      bottom
    } = dragAreaRef.current?.getBoundingClientRect();

    if (boundingBox) {
      event = event || window.event;
      if (
        event.clientX > left &&
        event.clientX < right &&
        event.clientY > top &&
        event.clientY < bottom
      ) {
        event.preventDefault();
        pos1 = pos3 - event.clientX;
        pos2 = pos4 - event.clientY;
        pos3 = event.clientX;
        pos4 = event.clientY;
        boundingBox.style.top = boundingBox.offsetTop - pos2 + "px";
        boundingBox.style.left = boundingBox.offsetLeft - pos1 + "px";
      }
    }
  };

https://codesandbox.io/s/react-typescript-forked-wges2?fontsize=14&hidenavigation=1&theme=dark

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

An external script containing icons is supposed to load automatically when the page is loaded, but unfortunately, the icons fail to display

Hello and thank you for taking the time to read my query! I am currently working in a Vue file, specifically in the App.vue where I am importing an external .js file containing icons. Here is how I import the script: let recaptchaScript2 = document.creat ...

When using Mongoose populate, it may either return an empty array or a list of Object

Currently, I am honing my skills in express.js by constructing a relational API but facing difficulty in populating keys within a schema. The structure involves having a list of properties, each with associated units. The units are linked through a proper ...

Hiding the keypad on an Android device in an Ionic app when user input is detected

I am currently utilizing the syncfusion ej2 Calendar plugin for a datepicker, but I am only using options such as selecting ranges like today, 1 month, or last 7 days from the plugin itself. The plugin provides dropdown options when the calendar is trigger ...

Discovering the process of retrieving API data upon a button click within Next.js using server-side rendering

Hi there, I'm fairly new to working with next.js and would greatly appreciate some assistance. I am trying to figure out how to fetch data from an API upon clicking a button in next.js on the server side. I understand that using onClick directly is ...

Tips for integrating Material UI with useRef

There seems to be an issue with the code, but I haven't been able to pinpoint exactly what it is. My question is: How do you properly use useRef with Material UI? I am attempting to create a login page. The code was functioning fine with the original ...

Issue with div not resizing as content is added

HTML Code <div class="container"> <div class="tip_text">A</div> <div class="tip_content">text example</div> </div> <br /><br /><br /> <div class="container"> <div class="tip_text ...

Using a combination of functions to ensure synchronicity in JavaScript operations

Here is the function I have created: $scope.saveManualResendDraft = function(todo) { if ($scope.editMode) { updateStartJobManual(); byeSendManualInputDirectly(); } else { console.log('bye'); } }; I have defin ...

What is the process for inserting a key value pair into a JSON object?

I am looking to enhance my JSON data by including a key-value pair in each object within the array. https://i.sstatic.net/48ptf.png My goal is to insert a key-value pair into every object in the students array. ...

Retrieving information from MongoDB queries using Node.js

I am facing an issue while trying to retrieve data from the find() method and use it outside the method. My goal is to incorporate this data into a JSON response. Unfortunately, my current code is not working as expected and the data is not accessible outs ...

Why isn't the POST operation functioning properly while all other CRUD operations are working?

After extensive testing with Postman, I found that all CRUD operations are functioning correctly, including POST. However, the issue arises when trying to make a POST request in the frontend app. Despite hours of debugging, I am still encountering errors. ...

Contrasts in functionality between Next.js and React when building a form

Currently, I am diving into the world of react/nextjs and have encountered a stumbling block while trying to implement a react tutorial in nextjs. My goal is to build a simple form for submitting data, so I thought this tutorial would be perfect for me. ...

Failed to store item in localStorage

After successfully setting an object to localStorage, the value of the object stays null. I suspect that my use of async/await is causing this issue. I can confirm that I am correctly setting the state, as when I log the user in and navigate to the index ...

Is there a significant distinction between value and defaultValue in React JS?

React's homepage features the final illustration (A Component Using External Plugins) with a textarea: <textarea id="markdown-content" onChange={this.handleChange} defaultValue={this.state.value} /> While typing, the ...

Error: The function m.easing[this.easing] is not defined

I have been working on creating anchor link scrolling and tooltip display using bootstrap, but I am encountering an issue. $(window).scroll(function(){ if ($(window).scrollTop() >= 100) { $('#header').addClass('fixed'); ...

I am experiencing difficulty in detecting variable changes within my $scope function

I'm encountering an issue where a variable isn't being updated in a $scope function when there's a state change event. Despite seeing the variable update in the event listener, it doesn't reflect in the function. The code snippet in qu ...

Revamp the current webpage to display attribute values in textual format

As I peruse a webpage, I notice that there is room for improvement in terms of user-friendliness. The page is filled with a list of movie titles, each accompanied by a link to IMDb. However, the IMDB user rating is only visible when hovering over the titl ...

Display a message box in the external window just before the close event

I am trying to implement a message box that will appear when the user clicks the (X) button of an Ext window. However, I am facing an issue where the window closes before the message box is shown. Below is the code snippet I have written: var assignReport ...

Gain access to PowerBI reports effortlessly without the need to input any credentials

Seeking guidance on calling Power BI reports from an ASP.NET C# web application while passing credentials, specifically without utilizing Azure AD. Access has been granted to certain users in the Power BI Service workspace with view permissions. We aim t ...

What is the best way to incorporate material-ui icons into my project?

I'm trying to incorporate an icon inside an IconButton, like so: <IconButton > <SearchIcon/> </IconButton> After adding @material-ui/icons to my package.json file and importing the necessary components: import IconButton from ...

How can I customize the visibility toggles for the password input field in Angular Material?

Currently immersed in the Angular 15 migration process... Today, I encountered an issue with a password input that displays two eyes the first time something is entered in the field. The HTML code for this is as follows: <mat-form-field appearance=&qu ...