3

Based on the create-react-app template, I'm trying to implement a very basic drag / drop scenario. My App.js currently looks like this:

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  render() {
    const myStyle = {
      height: '100px',
      width: '200px',
      top: '50px',
      left: '100px',
      position: 'absolute',
      borderStyle: 'solid',
      borderColor: 'blue',      
    };

    return (

      <div className="App">        
          <div style={myStyle} draggable>test</div>
          <div>test2</div>        
      </div>
    );
  }
}

export default App;

My question is that, from all the tutorials and documentation that I've seen, I understood the addition of the draggable property to cause the element to be draggable, however, it is not.

What additional properties need to be set to make an object draggable? (I'm not interested in dropping anything at this stage.)

3 Answers3

4

This can be a core implementation of the drag behaviour in React. It needs enhancements of course, plus does not handle dropping yet:

const { useRef } = React

const App = () => {
  const elemRef = useRef(null)
  const dragProps = useRef()
  
  const initialiseDrag = event => {
    const { target, clientX, clientY } = event
    const { offsetTop, offsetLeft } = target
    const { left, top } = elemRef.current.getBoundingClientRect()
    
    dragProps.current = {
      dragStartLeft: left - offsetLeft,
      dragStartTop: top - offsetTop,
      dragStartX: clientX,
      dragStartY: clientY
    }
    window.addEventListener('mousemove', startDragging, false)
    window.addEventListener('mouseup', stopDragging, false)
  }
  
  
  const startDragging = ({ clientX, clientY }) => {    
    elemRef.current.style.transform = `translate(${dragProps.current.dragStartLeft + clientX - dragProps.current.dragStartX}px, ${dragProps.current.dragStartTop + clientY - dragProps.current.dragStartY}px)`
  } 

  const stopDragging = () => {
    window.removeEventListener('mousemove', startDragging, false)
    window.removeEventListener('mouseup', stopDragging, false)
  }
  
  return (
    <div
      onMouseDown={initialiseDrag}
      ref={elemRef}
      >
      DragMe
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'));
div {
  cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
gazdagergo
  • 6,187
  • 1
  • 31
  • 45
  • I realise I could roll my own implementation, but I thought it should be possible to use the `draggable` property. Are you saying that React doesn't work with the `draggable` property built into HTML5? –  Jan 07 '19 at 18:00
  • `draggable` do work in react too but this implementation gives you more control over the drag coordinates for further processing. – gazdagergo Jan 07 '19 at 18:23
  • I've realised that I probably will need to end up with something like this, so it is very useful... I would still like to know why draggable doesn't work, though –  Jan 08 '19 at 12:47
  • Nice. If you are satisfied with the answer, please, upvote it. If entirely solves your problem also please mark it as accepted answer. Thanks in advance. Concering the draggable unfortunatelly I do not have too many experience, but as it is a native browser feature it do not allow too much control via javascript I think. – gazdagergo Jan 08 '19 at 13:11
  • I definitely will upvote. However, given that my question relates to why the draggable property does not work, this can't really be an accepted answer, because it doesn't answer that question. –  Jan 09 '19 at 14:09
  • 1
    This helped me to implement a custom range slider(without using an input type range), Thank you! – Ranjith Kumar Aug 19 '21 at 15:57
0

As I cannot run your current ReactJS application, I have pieced together a short example to show different instances of the drag and drop functionality.

As you can see by the example setting the draggable attribute to your element should make the element draggable, as it would look dragging an image on a typical webpage.

Can you confirm that when dragging your element, it doesn't move at all as seen in the code snippet for the not draggable box?

var draggable = document.getElementById('draggable');

function onDragStart(event) {
    event.dataTransfer.setData('text/html', null); //cannot be empty string
    var counter = document.getElementById('counter');
    counter.innerText = parseInt(counter.innerText, 10) + 1;
}

draggable.addEventListener('dragstart', onDragStart, false);
#draggable{
    width: 100px;
    height: 100px;
    background: blue;
    margin: 10px 5px;
}

#notdraggable{
    width: 100px;
    height: 100px;
    background: red;
    margin: 10px 5px;
}

#draggableNDT{
      width: 100px;
    height: 100px;
    background: green;
    margin: 10px 5px;
} 
   <div>Draggable (<span id='counter'>0</span>)</div>
    <div id='draggable' draggable='true'></div>
    
    <div><pre>Draggable (No DataTransfer)</div>
    <div id='draggableNDT' draggable></div>
    
    <div><pre>Not Draggable</div>
    <div id='notdraggable' draggable='false'></div>
Dean Meehan
  • 2,511
  • 22
  • 36
  • I'm just providing a complete answer. In the link provided you can also see that you need to create a method for the drag event handler as well as adding the draggable tag to the HTML – Dean Meehan Jan 07 '19 at 16:05
  • It is not a complete answer. And answers pointing to external websites are not answers at all. They should be comments instead – quirimmo Jan 07 '19 at 16:08
  • Are you saying that you /need/ to create that handler? I have tried that and it doesn't make a difference, but I was under the impression it was not necessary. –  Jan 07 '19 at 16:12
  • I've updated the answer to a more complete answer, Can you confirm that when dragging your element, it doesn't move at all as seen in the code snippet for the not draggable box? – Dean Meehan Jan 07 '19 at 16:51
  • I do not see the reason why to downvote this answer guys. This is a possible approach. If do not perfectly fit the needs of the question owner still gives us a valuable input. If there is an actual error in it, pls comment your suggestion to fix it, do not downvote. – gazdagergo Jan 07 '19 at 18:30
  • I can confirm that dragging the element doesn't move at all. Interestingly, only your draggable element above actually exhibits this behaviour. The 'draggable NDT' does not (tries it in Chrome and FF). I've tried to copy the parts that look different from your draggable example, but to no avail. My only conclusion is that React is the difference here – Paul Michaels Jan 08 '19 at 09:07
0

You can checkout react-draggable library, just wrap component in Draggable component

Install npm i react-draggable

Import import Draggable from 'react-draggable'

Usage:

<Draggable 
   axis="both"
   cancel="input, textarea, span, label"
>
  <div style={myStyle}>test</div>
</Draggable>
Declan
  • 51
  • 2