Top Related Projects
A draggable and resizable grid layout with responsive breakpoints, for React.
Beautiful and accessible drag and drop for lists with React
Drag and Drop for React
A set of higher-order components to turn any list into an animated, accessible and touch-friendly sortable list✌️
🖱 A resizable and draggable component for React.
Moveable! Draggable! Resizable! Scalable! Rotatable! Warpable! Pinchable! Groupable! Snappable!
Quick Overview
React-Draggable is a lightweight, performant drag and drop library for React applications. It provides a simple way to make DOM elements draggable, with support for both mouse and touch events, making it suitable for desktop and mobile applications.
Pros
- Easy to integrate with existing React projects
- Supports both mouse and touch events for broad device compatibility
- Highly customizable with various props and callbacks
- Lightweight and performant, with minimal dependencies
Cons
- Limited to dragging functionality; doesn't include features like resizing or sorting
- May require additional setup for complex use cases or specific layouts
- Documentation could be more comprehensive for advanced scenarios
- Occasional issues with nested draggable elements
Code Examples
- Basic draggable element:
import React from 'react';
import Draggable from 'react-draggable';
function App() {
return (
<Draggable>
<div>I can be dragged anywhere</div>
</Draggable>
);
}
- Draggable with bounds:
import React from 'react';
import Draggable from 'react-draggable';
function App() {
return (
<Draggable bounds="parent">
<div>I can only be dragged within my parent</div>
</Draggable>
);
}
- Draggable with event handlers:
import React from 'react';
import Draggable from 'react-draggable';
function App() {
const handleStart = (e, data) => console.log('Drag started', data);
const handleDrag = (e, data) => console.log('Dragging', data);
const handleStop = (e, data) => console.log('Drag stopped', data);
return (
<Draggable onStart={handleStart} onDrag={handleDrag} onStop={handleStop}>
<div>Drag me and check the console</div>
</Draggable>
);
}
Getting Started
-
Install the package:
npm install react-draggable
-
Import and use in your React component:
import React from 'react'; import Draggable from 'react-draggable'; function MyComponent() { return ( <Draggable> <div>Drag me!</div> </Draggable> ); } export default MyComponent;
-
Customize as needed using props and event handlers.
Competitor Comparisons
A draggable and resizable grid layout with responsive breakpoints, for React.
Pros of react-grid-layout
- Provides a complete grid layout system with resizing and dragging capabilities
- Offers responsive breakpoints for different screen sizes
- Includes built-in collision detection and prevention
Cons of react-grid-layout
- More complex API and setup compared to react-draggable
- Heavier in terms of bundle size and performance impact
- May be overkill for simple draggable requirements
Code Comparison
react-grid-layout:
import GridLayout from 'react-grid-layout';
<GridLayout
className="layout"
layout={layout}
cols={12}
rowHeight={30}
width={1200}
>
<div key="a">Item A</div>
<div key="b">Item B</div>
</GridLayout>
react-draggable:
import Draggable from 'react-draggable';
<Draggable
axis="both"
handle=".handle"
defaultPosition={{x: 0, y: 0}}
grid={[25, 25]}
scale={1}
>
<div>
<div className="handle">Drag from here</div>
<div>This content will be draggable</div>
</div>
</Draggable>
react-grid-layout offers a more comprehensive solution for creating complex, responsive grid layouts with draggable and resizable elements. It's ideal for dashboard-like interfaces or applications requiring precise control over element positioning. However, it comes with a steeper learning curve and higher complexity.
react-draggable, on the other hand, focuses solely on making elements draggable. It's simpler to implement and lighter in weight, making it a better choice for basic dragging functionality or when you need more control over the dragging behavior of individual elements.
Beautiful and accessible drag and drop for lists with React
Pros of react-beautiful-dnd
- Provides a more natural and fluid drag-and-drop experience
- Offers better accessibility features out of the box
- Includes built-in animations and visual feedback during drag operations
Cons of react-beautiful-dnd
- Less flexible for custom layouts or grid-based positioning
- May have a steeper learning curve due to its specific API and concepts
- Limited to vertical lists and horizontal lists, not suited for free-form dragging
Code Comparison
react-beautiful-dnd:
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="list">
{(provided) => (
<ul {...provided.droppableProps} ref={provided.innerRef}>
{items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided) => (
<li ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
{item.content}
</li>
)}
</Draggable>
))}
{provided.placeholder}
</ul>
)}
</Droppable>
</DragDropContext>
react-draggable:
<Draggable
axis="both"
handle=".handle"
defaultPosition={{x: 0, y: 0}}
position={null}
grid={[25, 25]}
scale={1}
onStart={handleStart}
onDrag={handleDrag}
onStop={handleStop}>
<div>
<div className="handle">Drag from here</div>
<div>This content will be draggable</div>
</div>
</Draggable>
Drag and Drop for React
Pros of react-dnd
- More flexible and powerful for complex drag-and-drop scenarios
- Supports touch devices and keyboard interactions out of the box
- Provides a higher level of abstraction with drag sources and drop targets
Cons of react-dnd
- Steeper learning curve due to its more complex API
- Requires more setup and boilerplate code for basic functionality
- May be overkill for simple drag-and-drop requirements
Code Comparison
react-dnd:
import { useDrag, useDrop } from 'react-dnd';
const [{ isDragging }, drag] = useDrag(() => ({
type: 'ITEM',
item: { id: props.id },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
}));
react-draggable:
import Draggable from 'react-draggable';
<Draggable
axis="x"
handle=".handle"
defaultPosition={{x: 0, y: 0}}
position={null}
grid={[25, 25]}
scale={1}
>
<div>Draggable content</div>
</Draggable>
A set of higher-order components to turn any list into an animated, accessible and touch-friendly sortable list✌️
Pros of react-sortable-hoc
- Specialized for sortable lists and grids
- Supports both vertical and horizontal sorting
- Provides animation and auto-scrolling capabilities
Cons of react-sortable-hoc
- Less flexible for general dragging tasks
- May have a steeper learning curve for simple use cases
- Limited to sorting within a container
Code Comparison
react-sortable-hoc:
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
const SortableItem = SortableElement(({value}) => <li>{value}</li>);
const SortableList = SortableContainer(({items}) => (
<ul>
{items.map((value, index) => (
<SortableItem key={`item-${index}`} index={index} value={value} />
))}
</ul>
));
react-draggable:
import Draggable from 'react-draggable';
const DraggableComponent = () => (
<Draggable>
<div>I can be dragged anywhere!</div>
</Draggable>
);
react-sortable-hoc is more suited for creating sortable lists or grids, while react-draggable offers more general-purpose dragging functionality. The choice between them depends on the specific requirements of your project.
🖱 A resizable and draggable component for React.
Pros of react-rnd
- Combines dragging and resizing functionality in a single component
- Supports both controlled and uncontrolled modes for more flexibility
- Includes built-in touch support for mobile devices
Cons of react-rnd
- Less focused on grid-based layouts compared to react-grid-layout
- May have a steeper learning curve due to more configuration options
- Smaller community and fewer contributors compared to react-draggable
Code Comparison
react-rnd:
<Rnd
default={{
x: 0, y: 0,
width: 320, height: 200
}}
>
Resizable and draggable content
</Rnd>
react-draggable:
<Draggable>
<div>Draggable content</div>
</Draggable>
react-rnd combines dragging and resizing in a single component, while react-draggable focuses solely on dragging functionality. react-rnd requires more configuration but offers more built-in features. react-draggable is simpler to use for basic dragging needs but may require additional components or libraries for resizing capabilities.
Both libraries are well-maintained and offer good performance, but react-draggable has a larger community and more frequent updates. The choice between them depends on specific project requirements, such as the need for combined dragging and resizing or preference for simplicity versus feature richness.
Moveable! Draggable! Resizable! Scalable! Rotatable! Warpable! Pinchable! Groupable! Snappable!
Pros of Moveable
- More versatile, supporting not just dragging but also resizing, rotating, and other transformations
- Framework-agnostic, can be used with various JavaScript libraries or vanilla JS
- Extensive set of events and hooks for fine-grained control over interactions
Cons of Moveable
- Steeper learning curve due to its more comprehensive feature set
- Potentially higher performance overhead for simpler use cases
- Less React-specific optimizations compared to React Draggable
Code Comparison
React Draggable:
import Draggable from 'react-draggable';
<Draggable>
<div>I can be dragged anywhere</div>
</Draggable>
Moveable:
import Moveable from "moveable";
const moveable = new Moveable(document.body, {
target: document.querySelector(".target"),
draggable: true,
});
moveable.on("drag", ({ target, transform }) => {
target.style.transform = transform;
});
Both libraries offer drag functionality, but Moveable provides a more low-level API that can be used in various contexts. React Draggable is more tightly integrated with React and offers a simpler API for basic dragging needs. Moveable's approach allows for more complex interactions and transformations beyond just dragging.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
React-Draggable
A simple component for making elements draggable.
<Draggable>
<div>I can now be moved around!</div>
</Draggable>
Version | Compatibility |
---|---|
4.x | React 16.3+ |
3.x | React 15-16 |
2.x | React 0.14 - 15 |
1.x | React 0.13 - 0.14 |
0.x | React 0.10 - 0.13 |
Technical Documentation
- Installing
- Exports
- Draggable
- Draggable Usage
- Draggable API
- Controlled vs. Uncontrolled
- DraggableCore
- DraggableCore API
Installing
$ npm install react-draggable
If you aren't using browserify/webpack, a
UMD version of react-draggable is available. It is updated per-release only.
This bundle is also what is loaded when installing from npm. It expects external React
and ReactDOM
.
If you want a UMD version of the latest master
revision, you can generate it yourself from master by cloning this
repository and running $ make
. This will create umd dist files in the dist/
folder.
Exports
The default export is <Draggable>
. At the .DraggableCore
property is <DraggableCore>
.
Here's how to use it:
// ES6
import Draggable from 'react-draggable'; // The default
import {DraggableCore} from 'react-draggable'; // <DraggableCore>
import Draggable, {DraggableCore} from 'react-draggable'; // Both at the same time
// CommonJS
let Draggable = require('react-draggable');
let DraggableCore = Draggable.DraggableCore;
<Draggable>
A <Draggable>
element wraps an existing element and extends it with new event handlers and styles.
It does not create a wrapper element in the DOM.
Draggable items are moved using CSS Transforms. This allows items to be dragged regardless of their current positioning (relative, absolute, or static). Elements can also be moved between drags without incident.
If the item you are dragging already has a CSS Transform applied, it will be overwritten by <Draggable>
. Use
an intermediate wrapper (<Draggable><span>...</span></Draggable>
) in this case.
Draggable Usage
View the Demo and its source for more.
import React from 'react';
import ReactDOM from 'react-dom';
import Draggable from 'react-draggable';
class App extends React.Component {
eventLogger = (e: MouseEvent, data: Object) => {
console.log('Event: ', e);
console.log('Data: ', data);
};
render() {
return (
<Draggable
axis="x"
handle=".handle"
defaultPosition={{x: 0, y: 0}}
position={null}
grid={[25, 25]}
scale={1}
onStart={this.handleStart}
onDrag={this.handleDrag}
onStop={this.handleStop}>
<div>
<div className="handle">Drag from here</div>
<div>This readme is really dragging on...</div>
</div>
</Draggable>
);
}
}
ReactDOM.render(<App/>, document.body);
Draggable API
The <Draggable/>
component transparently adds draggability to its children.
Note: Only a single child is allowed or an Error will be thrown.
For the <Draggable/>
component to correctly attach itself to its child, the child element must provide support
for the following props:
style
is used to give the transform css to the child.className
is used to apply the proper classes to the object being dragged.onMouseDown
,onMouseUp
,onTouchStart
, andonTouchEnd
are used to keep track of dragging state.
React.DOM elements support the above properties by default, so you may use those elements as children without any changes. If you wish to use a React component you created, you'll need to be sure to transfer prop.
<Draggable>
Props:
//
// Types:
//
type DraggableEventHandler = (e: Event, data: DraggableData) => void | false;
type DraggableData = {
node: HTMLElement,
// lastX + deltaX === x
x: number, y: number,
deltaX: number, deltaY: number,
lastX: number, lastY: number
};
//
// Props:
//
{
// If set to `true`, will allow dragging on non left-button clicks.
allowAnyClick: boolean,
// Default `false` and default behavior before 4.5.0.
// If set to `true`, the 'touchstart' event will not be prevented,
// which will allow scrolling inside containers. We recommend
// using the 'handle' / 'cancel' props when possible instead of enabling this.
//
// See https://github.com/react-grid-layout/react-draggable/issues/728
allowMobileScroll: boolean,
// Determines which axis the draggable can move. This only affects
// flushing to the DOM. Callbacks will still include all values.
// Accepted values:
// - `both` allows movement horizontally and vertically (default).
// - `x` limits movement to horizontal axis.
// - `y` limits movement to vertical axis.
// - 'none' stops all movement.
axis: string,
// Specifies movement boundaries. Accepted values:
// - `parent` restricts movement within the node's offsetParent
// (nearest node with position relative or absolute), or
// - a selector, restricts movement within the targeted node
// - An object with `left, top, right, and bottom` properties.
// These indicate how far in each direction the draggable
// can be moved.
bounds: {left?: number, top?: number, right?: number, bottom?: number} | string,
// Specifies a selector to be used to prevent drag initialization. The string is passed to
// Element.matches, so it's possible to use multiple selectors like `.first, .second`.
// Example: '.body'
cancel: string,
// Class names for draggable UI.
// Default to 'react-draggable', 'react-draggable-dragging', and 'react-draggable-dragged'
defaultClassName: string,
defaultClassNameDragging: string,
defaultClassNameDragged: string,
// Specifies the `x` and `y` that the dragged item should start at.
// This is generally not necessary to use (you can use absolute or relative
// positioning of the child directly), but can be helpful for uniformity in
// your callbacks and with css transforms.
defaultPosition: {x: number, y: number},
// If true, will not call any drag handlers.
disabled: boolean,
// Default `true`. Adds "user-select: none" while dragging to avoid selecting text.
enableUserSelectHack: boolean,
// Specifies the x and y that dragging should snap to.
grid: [number, number],
// Specifies a selector to be used as the handle that initiates drag.
// Example: '.handle'
handle: string,
// If desired, you can provide your own offsetParent for drag calculations.
// By default, we use the Draggable's offsetParent. This can be useful for elements
// with odd display types or floats.
offsetParent: HTMLElement,
// Called whenever the user mouses down. Called regardless of handle or
// disabled status.
onMouseDown: (e: MouseEvent) => void,
// Called when dragging starts. If `false` is returned any handler,
// the action will cancel.
onStart: DraggableEventHandler,
// Called while dragging.
onDrag: DraggableEventHandler,
// Called when dragging stops.
onStop: DraggableEventHandler,
// If running in React Strict mode, ReactDOM.findDOMNode() is deprecated.
// Unfortunately, in order for <Draggable> to work properly, we need raw access
// to the underlying DOM node. If you want to avoid the warning, pass a `nodeRef`
// as in this example:
//
// function MyComponent() {
// const nodeRef = React.useRef(null);
// return (
// <Draggable nodeRef={nodeRef}>
// <div ref={nodeRef}>Example Target</div>
// </Draggable>
// );
// }
//
// This can be used for arbitrarily nested components, so long as the ref ends up
// pointing to the actual child DOM node and not a custom component.
//
// For rich components, you need to both forward the ref *and props* to the underlying DOM
// element. Props must be forwarded so that DOM event handlers can be attached.
// For example:
//
// const Component1 = React.forwardRef(function (props, ref) {
// return <div {...props} ref={ref}>Nested component</div>;
// });
//
// const nodeRef = React.useRef(null);
// <DraggableCore onDrag={onDrag} nodeRef={nodeRef}>
// <Component1 ref={nodeRef} />
// </DraggableCore>
//
// Thanks to react-transition-group for the inspiration.
//
// `nodeRef` is also available on <DraggableCore>.
nodeRef: React.Ref<typeof React.Component>,
// Much like React form elements, if this property is present, the item
// becomes 'controlled' and is not responsive to user input. Use `position`
// if you need to have direct control of the element.
position: {x: number, y: number}
// A position offset to start with. Useful for giving an initial position
// to the element. Differs from `defaultPosition` in that it does not
// affect the position returned in draggable callbacks, and in that it
// accepts strings, like `{x: '10%', y: '10%'}`.
positionOffset: {x: number | string, y: number | string},
// Specifies the scale of the canvas your are dragging this element on. This allows
// you to, for example, get the correct drag deltas while you are zoomed in or out via
// a transform or matrix in the parent of this element.
scale: number
}
Note that sending className
, style
, or transform
as properties will error - set them on the child element
directly.
Controlled vs. Uncontrolled
<Draggable>
is a 'batteries-included' component that manages its own state. If you want to completely
control the lifecycle of the component, use <DraggableCore>
.
For some users, they may want the nice state management that <Draggable>
provides, but occasionally want
to programmatically reposition their components. <Draggable>
allows this customization via a system that
is similar to how React handles form components.
If the prop position: {x: number, y: number}
is defined, the <Draggable>
will ignore its internal state and use
the provided position instead. Alternatively, you can seed the position using defaultPosition
. Technically, since
<Draggable>
works only on position deltas, you could also seed the initial position using CSS top/left
.
We make one modification to the React philosophy here - we still allow dragging while a component is controlled.
We then expect you to use at least an onDrag
or onStop
handler to synchronize state.
To disable dragging while controlled, send the prop disabled={true}
- at this point the <Draggable>
will operate
like a completely static component.
<DraggableCore>
For users that require absolute control, a <DraggableCore>
element is available. This is useful as an abstraction
over touch and mouse events, but with full control. <DraggableCore>
has no internal state.
See React-Resizable and React-Grid-Layout for some usage examples.
<DraggableCore>
is a useful building block for other libraries that simply want to abstract browser-specific
quirks and receive callbacks when a user attempts to move an element. It does not set styles or transforms
on itself and thus must have callbacks attached to be useful.
DraggableCore API
<DraggableCore>
takes a limited subset of options:
{
allowAnyClick: boolean,
allowMobileScroll: boolean,
cancel: string,
disabled: boolean,
enableUserSelectHack: boolean,
offsetParent: HTMLElement,
grid: [number, number],
handle: string,
onStart: DraggableEventHandler,
onDrag: DraggableEventHandler,
onStop: DraggableEventHandler,
onMouseDown: (e: MouseEvent) => void,
scale: number
}
Note that there is no start position. <DraggableCore>
simply calls drag
handlers with the below parameters,
indicating its position (as inferred from the underlying MouseEvent) and deltas. It is up to the parent
to set actual positions on <DraggableCore>
.
Drag callbacks (onStart
, onDrag
, onStop
) are called with the same arguments as <Draggable>
.
Contributing
- Fork the project
- Run the project in development mode:
$ npm run dev
- Make changes.
- Add appropriate tests
$ npm test
- If tests don't pass, make them pass.
- Update README with appropriate docs.
- Commit and PR
Release checklist
- Update CHANGELOG
make release-patch
,make release-minor
, ormake-release-major
make publish
License
MIT
Top Related Projects
A draggable and resizable grid layout with responsive breakpoints, for React.
Beautiful and accessible drag and drop for lists with React
Drag and Drop for React
A set of higher-order components to turn any list into an animated, accessible and touch-friendly sortable list✌️
🖱 A resizable and draggable component for React.
Moveable! Draggable! Resizable! Scalable! Rotatable! Warpable! Pinchable! Groupable! Snappable!
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot