const {ReactDraggable: Draggable, React, ReactDOM} = window; class App extends React.Component { state = { activeDrags: 0, deltaPosition: { x: 0, y: 0 }, controlledPosition: { x: -400, y: 200 } }; handleDrag = (e, ui) => { const {x, y} = this.state.deltaPosition; this.setState({ deltaPosition: { x: x + ui.deltaX, y: y + ui.deltaY, } }); }; onStart = () => { this.setState({activeDrags: ++this.state.activeDrags}); }; onStop = () => { this.setState({activeDrags: --this.state.activeDrags}); }; onDrop = (e) => { this.setState({activeDrags: --this.state.activeDrags}); if (e.target.classList.contains("drop-target")) { alert("Dropped!"); e.target.classList.remove('hovered'); } }; onDropAreaMouseEnter = (e) => { if (this.state.activeDrags) { e.target.classList.add('hovered'); } } onDropAreaMouseLeave = (e) => { e.target.classList.remove('hovered'); } // For controlled component adjustXPos = (e) => { e.preventDefault(); e.stopPropagation(); const {x, y} = this.state.controlledPosition; this.setState({controlledPosition: {x: x - 10, y}}); }; adjustYPos = (e) => { e.preventDefault(); e.stopPropagation(); const {controlledPosition} = this.state; const {x, y} = controlledPosition; this.setState({controlledPosition: {x, y: y - 10}}); }; onControlledDrag = (e, position) => { const {x, y} = position; this.setState({controlledPosition: {x, y}}); }; onControlledDragStop = (e, position) => { this.onControlledDrag(e, position); this.onStop(); }; render() { const dragHandlers = {onStart: this.onStart, onStop: this.onStop}; const {deltaPosition, controlledPosition} = this.state; return (

React Draggable

Active DragHandlers: {this.state.activeDrags}

Demo Source

I can be dragged anywhere
I can only be dragged horizonally (x axis)
I can only be dragged vertically (y axis)
false}>
I don't want to be dragged
I track my deltas
x: {deltaPosition.x.toFixed(0)}, y: {deltaPosition.y.toFixed(0)}
Drag here
You must click my handle to drag me
Drag here
I have long scrollable content with a handle {'\n' + Array(40).fill('x').join('\n')}
Can't drag here
Dragging here works
I snap to a 25 x 25 grid
I snap to a 50 x 50 grid
I can only be moved 100px in any direction.
I can detect drops from the next box.
I can be dropped onto another box.
I can only be moved within my offsetParent.

Both parent padding and child margin work properly.
I also can only be moved within my offsetParent.

Both parent padding and child margin work properly.
I can only be moved within the confines of the body element.
I already have an absolute position.
I use rem instead of px for my transforms. I also have absolute positioning.

I depend on a CSS hack to avoid double absolute positioning.
{"I have a default position of {x: 25, y: 25}, so I'm slightly offset."}
{'I have a default position based on percents {x: \'-10%\', y: \'-10%\'}, so I\'m slightly offset.'}
My position can be changed programmatically.
I have a drag handler to sync state.
Adjust x ({controlledPosition.x})
Adjust y ({controlledPosition.y})
My position can be changed programmatically.
I have a dragStop handler to sync state.
Adjust x ({controlledPosition.x})
Adjust y ({controlledPosition.y})
); } } class RemWrapper extends React.Component { // PropTypes is not available in this environment, but here they are. // static propTypes = { // style: PropTypes.shape({ // transform: PropTypes.string.isRequired // }), // children: PropTypes.node.isRequired, // remBaseline: PropTypes.number, // } translateTransformToRem(transform, remBaseline = 16) { const convertedValues = transform.replace('translate(', '').replace(')', '') .split(',') .map(px => px.replace('px', '')) .map(px => parseInt(px, 10) / remBaseline) .map(x => `${x}rem`) const [x, y] = convertedValues return `translate(${x}, ${y})` } render() { const { children, remBaseline = 16, style } = this.props const child = React.Children.only(children) const editedStyle = { ...child.props.style, ...style, transform: this.translateTransformToRem(style.transform, remBaseline), } return React.cloneElement(child, { ...child.props, ...this.props, style: editedStyle }) } } ReactDOM.render(, document.getElementById('container'));