react-use-drag-and-drop
v2.0.4
Published
Allow you drag and drop any html or svg element for react.
Downloads
109
Readme
🚀 Why use this library?
Dragging elements on the web often comes with performance costs. Many libraries trigger React re-renders on every pixel the mouse moves, causing UI jank and lag.
react-use-drag-and-drop is different.
- ⚡ High Performance: Uses Observables and direct DOM event listeners to handle high-frequency events (like
dragover). React only re-renders when it strictly needs to (e.g., when the drop state actually changes). - 🎣 Hooks First: Simple
useDraganduseDrophooks that fit naturally into your functional components. - 🧠 Headless: We handle the logic, you handle the UI. No pre-styled components or rigid structures.
- 🛡️ Type Safe: Written in TypeScript with full type definitions included.
📦 Install
npm install --save react-use-drag-and-drop
# or
yarn add react-use-drag-and-drop
⚡ Quick Start
1. Wrap your application
Add the DragAndDropProvider at the root (or near the root) of your application. This manages the shared state without polluting your component tree.
import { DragAndDropProvider } from 'react-use-drag-and-drop';
const App = () => {
return (
<DragAndDropProvider>
<YourApp />
</DragAndDropProvider>
);
};
2. Make an element Draggable
Use the useDrag hook. Attach the reference to the DOM element you want to move.
import React, { useRef } from 'react';
import { useDrag } from 'react-use-drag-and-drop';
const DraggableCard = ({ id, title }) => {
const cardRef = useRef(null);
const { isDragging } = useDrag({
id,
element: cardRef,
data: { title, id }, // Data to be transferred
start: (data) => console.log('Started dragging', data),
end: (data) => console.log('Stopped dragging', data),
}, [title]); // Dependency array for updates
return (
<div
ref={cardRef}
style={{ opacity: isDragging ? 0.5 : 1 }}
>
{title}
</div>
);
};
3. Create a Drop Zone
Use the useDrop hook to handle incoming items.
import React, { useRef } from 'react';
import { useDrop } from 'react-use-drag-and-drop';
const DropZone = () => {
const zoneRef = useRef(null);
const [{ isDraggingOver }] = useDrop({
id: 'my-drop-zone',
element: zoneRef,
// Triggered when an item is dropped here
drop: (data, monitor) => {
console.log('Dropped item:', data);
console.log('Coordinates:', monitor.x, monitor.y);
},
// Triggered constantly while hovering (High perf)
hover: (data, monitor) => {
// Logic here runs without re-rendering the component!
}
});
return (
<div
ref={zoneRef}
style={{
border: isDraggingOver ? '2px dashed green' : '1px solid gray',
background: isDraggingOver ? '#eef' : 'white'
}}
>
{isDraggingOver ? 'Release to Drop!' : 'Drop items here'}
</div>
);
};
📖 API Reference
useDrag
const { isDragging, preview } = useDrag(options, deps);
Options
| Prop | Type | Description |
| --- | --- | --- |
| id | string | Required. Unique identifier for the draggable item. |
| element | RefObject<HTMLElement> | Required. React Ref attached to the DOM node. |
| data | T | The data payload to be transferred to the drop zone. |
| canDrag | boolean | (Optional) Toggle to enable/disable dragging. Default: true. |
| start | (data) => void | Callback when drag starts. |
| end | (data) => void | Callback when drag ends. |
Return
| Property | Type | Description |
| --- | --- | --- |
| isDragging | boolean | true if this specific item is currently being dragged. |
| preview | Function | Function to set a custom drag layer image/element. |
useDrop
const [{ isDraggingOver, isDraggingOverCurrent }] = useDrop(options, deps);
Options
| Prop | Type | Description |
| --- | --- | --- |
| id | string | Required. Unique identifier for the drop zone. |
| element | RefObject<HTMLElement> | Required. React Ref attached to the DOM node. |
| drop | (data, monitor) => void | Callback when a valid item is dropped. |
| hover | (data, monitor) => void | Callback fired continuously while an item hovers. |
| leave | (data, monitor) => void | Callback fired when an item leaves the zone. |
Return
| Property | Type | Description |
| --- | --- | --- |
| isDraggingOver | boolean | true if an item is hovering over this zone (or one of its descendant drop zones). |
| isDraggingOverCurrent | boolean | true ONLY if the item is hovering strictly over this zone (not a child). |
Nested drop zones: only the innermost drop zone under the cursor responds. When a draggable item is over a child drop zone, the event is stopped at that child, so parent zones do not fire
dragover,hover,droporleavefor that child, and theirisDraggingOverstaysfalse. UseisDraggingOverCurrentto distinguish "on this exact zone" from "on one of my children".
🤝 Contribute
We welcome contributions! Please follow these steps to run the project locally:
Clone the repo:
git clone https://github.com/lvsouza/react-use-drag-and-drop.gitInstall dependencies:
yarn installRun the example playground:
yarn devBuild the package:
yarn buildPublish the package:
npm publish
📄 License
MIT © Lucas Souza Dev
