react-draggable vs react-dnd vs sortablejs vs react-beautiful-dnd vs react-sortable-hoc
React Drag-and-Drop Libraries Comparison
1 Year
react-draggablereact-dndsortablejsreact-beautiful-dndreact-sortable-hoc
What's React Drag-and-Drop Libraries?

Drag-and-drop libraries in React provide developers with tools to implement drag-and-drop functionality in web applications. These libraries simplify the process of creating interactive UIs where users can move elements around, reorder lists, or transfer items between different containers. Each library has its own strengths and weaknesses, catering to various use cases, from simple draggable components to complex drag-and-drop interfaces with customizable behaviors and animations. Note that react-beautiful-dnd is now deprecated, so developers should consider alternatives like react-dnd, react-sortable-hoc, or sortablejs for long-term projects.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
react-draggable2,498,5979,140244 kB2452 years agoMIT
react-dnd2,331,80121,345231 kB463-MIT
sortablejs1,973,07130,253641 kB4994 months agoMIT
react-beautiful-dnd1,845,29133,7901.39 MB644-Apache-2.0
react-sortable-hoc486,82910,866-2934 years agoMIT
Feature Comparison: react-draggable vs react-dnd vs sortablejs vs react-beautiful-dnd vs react-sortable-hoc

Complexity and Use Case

  • react-draggable:

    Focuses solely on making elements draggable, making it the simplest option for basic use cases where drag-and-drop is needed without additional features.

  • react-dnd:

    Offers a more complex API that allows for intricate drag-and-drop scenarios, including nested drag sources and drop targets. It's ideal for applications that require advanced drag-and-drop capabilities.

  • sortablejs:

    A versatile library that can be used with any framework, sortablejs is lightweight and offers extensive customization options, making it suitable for a wide range of applications.

  • react-beautiful-dnd:

    Designed for simplicity and ease of use, react-beautiful-dnd is great for straightforward drag-and-drop lists, making it suitable for applications that prioritize user experience without complex interactions. However, react-beautiful-dnd is now deprecated, so consider using more actively maintained alternatives.

  • react-sortable-hoc:

    Provides a higher-order component pattern for creating sortable lists, making it easy to implement while keeping the component structure intact. Best for applications needing sortable lists without complex configurations.

Performance

  • react-draggable:

    Lightweight and efficient for simple draggable components, ensuring minimal performance overhead when used in applications.

  • react-dnd:

    Highly performant for complex interactions, but requires careful management of state and component updates to avoid performance bottlenecks in large applications.

  • sortablejs:

    Known for its high performance and low overhead, sortablejs is capable of handling large lists and complex interactions effectively.

  • react-beautiful-dnd:

    Optimized for performance with smooth animations and transitions, but may not handle very large lists as efficiently as other libraries due to its focus on user experience. Since it is now deprecated, it's recommended to move to alternatives for better long-term performance.

  • react-sortable-hoc:

    Efficient for sortable lists, but performance may vary based on the complexity of the list and the number of items being sorted.

Customization and Extensibility

  • react-draggable:

    Simple customization options for draggable elements, but lacks advanced features for drop targets or complex interactions.

  • react-dnd:

    Highly customizable, allowing developers to define their own drag-and-drop behaviors and interactions, making it suitable for complex applications.

  • sortablejs:

    Extensively customizable with a wide range of options for sorting and dragging, making it suitable for applications that require tailored behaviors.

  • react-beautiful-dnd:

    Offers limited customization options compared to others, focusing on providing a consistent and beautiful drag-and-drop experience out of the box. Since react-beautiful-dnd is deprecated, developers should consider more extensible solutions like react-dnd or sortablejs.

  • react-sortable-hoc:

    Provides a straightforward way to create sortable lists, but customization is limited to sorting behavior and does not extend to drag-and-drop interactions.

Accessibility

  • react-draggable:

    Basic accessibility support, but developers need to implement additional features for a fully accessible experience.

  • react-dnd:

    Accessibility features depend on the implementation, requiring developers to ensure that drag-and-drop interactions are accessible to all users.

  • sortablejs:

    Accessibility features are not built-in, necessitating additional work to ensure that drag-and-drop interactions are usable for all users.

  • react-beautiful-dnd:

    Built with accessibility in mind, providing keyboard navigation and screen reader support to ensure a better experience for all users. However, since it is now deprecated, developers should be aware that it may not receive future updates or support.

  • react-sortable-hoc:

    Accessibility support is limited, requiring developers to handle keyboard navigation and screen reader compatibility themselves.

Learning Curve

  • react-draggable:

    Very easy to use, making it ideal for beginners who want to implement basic draggable functionality without much overhead.

  • react-dnd:

    Has a steeper learning curve due to its complex API and flexibility, making it more suitable for experienced developers who need advanced features.

  • sortablejs:

    Straightforward to use, but may require additional effort to integrate with React properly, especially for more complex use cases.

  • react-beautiful-dnd:

    Easy to learn and implement, making it suitable for developers who want to quickly add drag-and-drop functionality without a steep learning curve. However, since react-beautiful-dnd is deprecated, developers should explore other options for a longer-term solution.

  • react-sortable-hoc:

    Moderate learning curve; while it simplifies the creation of sortable lists, developers need to understand higher-order components in React.

How to Choose: react-draggable vs react-dnd vs sortablejs vs react-beautiful-dnd vs react-sortable-hoc
  • react-draggable:

    Opt for react-draggable if you need basic draggable functionality without the overhead of a full drag-and-drop library. It's perfect for simple use cases where you want to make elements draggable without the need for drop targets or complex interactions.

  • react-dnd:

    Select react-dnd for more complex drag-and-drop interactions, especially when you need to manage multiple drag sources and drop targets. It offers a powerful API and is highly customizable, making it suitable for applications with intricate drag-and-drop requirements.

  • sortablejs:

    Choose sortablejs for a lightweight, performant solution that works with any framework, including React. It offers a rich set of features for sorting and dragging elements, making it suitable for applications that require extensive customization and performance.

  • react-beautiful-dnd:

    Choose react-beautiful-dnd for a simple, visually appealing drag-and-drop experience with built-in accessibility features. It's ideal for applications that require a straightforward implementation of drag-and-drop lists with a focus on aesthetics and user experience. However, please note that react-beautiful-dnd is now deprecated, and it is recommended to consider alternatives for new or ongoing projects.

  • react-sortable-hoc:

    Use react-sortable-hoc when you need to create sortable lists with minimal setup. It provides a higher-order component approach, making it easy to implement sortable lists while maintaining the React component structure.

README for react-draggable

React-Draggable

TravisCI Build Status Appveyor Build Status npm downloads gzip size version

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

$ 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, and onTouchEnd 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,

// 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,

// 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,
  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, or make-release-major
  • make publish

License

MIT