How can I help you?
Drag and Drop in React
2 Feb 202617 minutes to read
Drag and drop enables users to select one or more items and move them to a different location or onto another interface element by dragging with a mouse, touch, or pen input and releasing at the desired target location.
Syncfusion® React components support drag-and-drop interactions through two core utilities from the @syncfusion/ej2-base package: Draggable and Droppable. These utilities provide a flexible foundation for implementing custom drag-and-drop behaviors, including item reordering, drag handles, constrained movement, and drop target validation.
npm install @syncfusion/ej2-base --saveImport the required utilities in your component:
import { Draggable, Droppable } from '@syncfusion/ej2-base';Draggable
The Draggable utility transforms any DOM element into a draggable item by instantiating the Draggable class with a target element selector. This utility supports various configuration options to control drag behavior, including movement constraints, cloning, custom drag handles, and event callbacks. The example below demonstrates basic draggable functionality for a specified DOM element.
import * as React from 'react';
import { useEffect } from 'react';
import * as ReactDom from 'react-dom';
import { Draggable } from '@syncfusion/ej2-base';
function App() {
useEffect(() => {
let draggable = new Draggable(document.getElementById('element'), { clone: false });
}, []);
return (<div id='container'>
<div id='element'><p>Draggable Element</p></div>
</div>);
}
export default App;
ReactDom.render(<App />, document.getElementById('sample'));import * as React from 'react';
import { useEffect } from 'react';
import * as ReactDom from 'react-dom';
import { Draggable } from '@syncfusion/ej2-base';
function App() {
useEffect(() => {
let draggable: Draggable = new Draggable(document.getElementById('element'),{ clone: false });
},[])
return (
<div id='container'>
<div id='element'><p>Draggable Element</p></div>
</div>
);
}
export default App;
ReactDom.render(<App />, document.getElementById('sample'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Button</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="index.css" rel="stylesheet" />
<link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-base/styles/tailwind3.css" rel="stylesheet" />
<link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-react-buttons/styles/tailwind3.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
</head>
<body>
<div id='sample'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Clone draggable element
Create a visual copy of the dragged element during the drag operation by setting the clone property to true. When enabled, this renders a duplicate element that follows the cursor while the original element remains in its initial position. This is particularly useful for scenarios where the source item should persist, such as palette-based interfaces or template selection workflows.
import * as React from 'react';
import { useEffect } from 'react';
import * as ReactDom from 'react-dom';
import { Draggable } from '@syncfusion/ej2-base';
function App() {
useEffect(() => {
let draggable = new Draggable(document.getElementById('element'), { clone: true });
}, []);
return (<div id='container'>
<div id='element'><p>Draggable Element</p></div>
</div>);
}
export default App;
ReactDom.render(<App />, document.getElementById('sample'));import * as React from 'react';
import { useEffect } from 'react';
import * as ReactDom from 'react-dom';
import { Draggable } from '@syncfusion/ej2-base';
function App() {
useEffect(() => {
let draggable: Draggable = new Draggable(document.getElementById('element'),{ clone: true });
},[])
return (
<div id='container'>
<div id='element'><p>Draggable Element</p></div>
</div>
);
}
export default App;
ReactDom.render(<App />, document.getElementById('sample'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Button</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="index.css" rel="stylesheet" />
<link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-base/styles/tailwind3.css" rel="stylesheet" />
<link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-react-buttons/styles/tailwind3.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
</head>
<body>
<div id='sample'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Drag area
A drag area is a specific area within a user interface that is designated for drag and drop operations. When an object or element is dragged within a drag area, certain actions or events may be triggered.
Define a constrained drag region by setting the dragArea property to a valid CSS selector or DOM element reference. This restricts the draggable element’s movement to within the specified container boundaries, preventing it from being dragged outside the designated area. This is essential for maintaining layout integrity and creating bounded interaction zones. The example below demonstrates drag area constraint implementation.
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { useEffect } from 'react';
import { Draggable } from '@syncfusion/ej2-base';
function App() {
useEffect(() => {
let draggable = new Draggable(document.getElementById('draggable'), { clone: false, dragArea: "#droppable" });
}, []);
return (<div id='container'>
<div id='droppable'><p>Drag Area </p></div>
<div id='draggable'><p id='drag'>Draggable Element </p></div>
</div>);
}
export default App;
ReactDom.render(<App />, document.getElementById('sample'));import * as React from 'react';
import * as ReactDom from 'react-dom';
import { useEffect } from 'react';
import { Draggable } from '@syncfusion/ej2-base';
function App() {
useEffect(() => {
let draggable: Draggable = new Draggable(document.getElementById('draggable'),{ clone: false, dragArea: "#droppable" });
},[])
return (
<div id='container'>
<div id='droppable'><p>Drag Area </p></div>
<div id='draggable'><p id='drag'>Draggable Element </p></div>
</div>
);
}
export default App;
ReactDom.render(<App />, document.getElementById('sample'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Button</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="index.css" rel="stylesheet" />
<link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-base/styles/tailwind3.css" rel="stylesheet" />
<link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-react-buttons/styles/tailwind3.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
</head>
<body>
<div id='sample'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Droppable
A droppable zone is an area that accepts and responds to draggable elements when they are released over it. The Droppable utility converts any DOM element into a valid drop target, enabling interaction with draggable items.
When a draggable element is released over a droppable zone, the drop event is triggered. This event provides detailed information through its arguments, including references to the dragged element (droppedElement), the drop target (target), and the original drag source. This data enables implementation of actions such as appending elements, updating data models, applying visual feedback, or triggering state changes based on the drop interaction.
Refer to the following example to implement droppable zones with drag-and-drop interaction handling.
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { useEffect } from 'react';
import { Draggable, Droppable } from '@syncfusion/ej2-base';
function App() {
useEffect(() => {
let draggable = new Draggable(document.getElementById('draggable'), { clone: false });
let droppable = new Droppable(document.getElementById('droppable'), {
drop: (e) => {
e.droppedElement.querySelector('#drag').textContent = 'Dropped';
}
});
}, []);
return (<div id='container'>
<div id='droppable'><p>Droppable Target </p></div>
<div id='draggable'><p id='drag'>Draggable Element </p></div>
</div>);
}
export default App;
ReactDom.render(<App />, document.getElementById('sample'));import * as React from 'react';
import * as ReactDom from 'react-dom';
import { useEffect } from 'react';
import { Draggable, Droppable, DropEventArgs } from '@syncfusion/ej2-base';
function App() {
useEffect(() => {
let draggable: Draggable = new Draggable(document.getElementById('draggable'),{ clone: false });
let droppable: Droppable = new Droppable(document.getElementById('droppable'), {
drop: (e: DropEventArgs) => {
e.droppedElement.querySelector('#drag').textContent = 'Dropped';
}
});
},[])
return (
<div id='container'>
<div id='droppable'><p>Droppable Target </p></div>
<div id='draggable'><p id='drag'>Draggable Element </p></div>
</div>
);
}
export default App;
ReactDom.render(<App />, document.getElementById('sample'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Button</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="index.css" rel="stylesheet" />
<link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-base/styles/tailwind3.css" rel="stylesheet" />
<link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-react-buttons/styles/tailwind3.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
</head>
<body>
<div id='sample'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>