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

Drag and drop libraries for React provide developers with tools to implement drag-and-drop functionality in their applications. These libraries offer APIs and components that handle mouse and touch events, allowing users to drag items from one location and drop them into another. They are useful for creating interactive interfaces, such as sortable lists, draggable panels, and file upload areas. These libraries often come with features like customizable drag previews, keyboard accessibility, and support for touch devices, making them versatile for various use cases. They help enhance user experience by providing intuitive ways to manipulate content on the screen.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
react-draggable2,902,696
9,231243 kB2432 months agoMIT
react-dnd2,416,934
21,548231 kB472-MIT
sortablejs2,043,854
30,718641 kB5079 months agoMIT
react-beautiful-dnd1,768,398
34,0301.39 MB644-Apache-2.0
react-sortable-hoc528,049
10,897-2904 years agoMIT
Feature Comparison: react-draggable vs react-dnd vs sortablejs vs react-beautiful-dnd vs react-sortable-hoc

Complexity and Customization

  • react-draggable:

    react-draggable is a lightweight library focused on making individual elements draggable. It provides basic customization options for drag behavior, such as constraints and handle elements, but it is not designed for complex drag-and-drop interactions or nested drag-and-drop functionality.

  • react-dnd:

    react-dnd is highly customizable and designed for complex drag-and-drop interactions. It provides a low-level API that allows developers to create highly specialized drag-and-drop experiences, making it suitable for applications that require detailed control over the behavior of draggable and droppable elements.

  • sortablejs:

    sortablejs is a lightweight and highly performant library for creating sortable lists and grids. It offers a range of customization options, including drag handles, animations, and event callbacks, making it flexible for various use cases while remaining easy to use.

  • react-beautiful-dnd:

    react-beautiful-dnd is designed for simplicity and ease of use, with a focus on providing a beautiful and accessible drag-and-drop experience out of the box. While it offers some customization options, it is not as flexible as react-dnd for complex use cases.

  • react-sortable-hoc:

    react-sortable-hoc is built for creating sortable lists and grids with minimal setup. It provides good customization options for sorting behavior, including the ability to customize the drag handle and drop animations, but it is primarily focused on sorting rather than general drag-and-drop functionality.

Performance

  • react-draggable:

    react-draggable is lightweight and has minimal impact on performance. It is ideal for applications that require simple dragging functionality without the overhead of a full drag-and-drop library.

  • react-dnd:

    react-dnd performance largely depends on how it is implemented. Since it is highly customizable, developers can optimize it for their specific use cases. However, its flexibility may introduce overhead if not used carefully, especially in complex drag-and-drop scenarios.

  • sortablejs:

    sortablejs is known for its high performance and low memory usage, making it one of the fastest libraries for creating sortable lists and grids. It is optimized for handling large lists and complex drag-and-drop interactions with minimal impact on performance.

  • react-beautiful-dnd:

    react-beautiful-dnd is optimized for performance, especially for lists and grids. However, it may experience performance issues with very large lists or highly nested drag-and-drop structures due to its focus on accessibility and visual fidelity.

  • react-sortable-hoc:

    react-sortable-hoc is designed to be performant, especially for sortable lists. It uses a virtual DOM approach to minimize re-renders during dragging, making it suitable for most use cases without significant performance drawbacks.

Accessibility

  • react-draggable:

    react-draggable offers basic accessibility features, but it is primarily focused on making elements draggable. Developers need to implement additional accessibility features, such as keyboard navigation and aria attributes, to make draggable elements fully accessible.

  • react-dnd:

    react-dnd provides accessibility features, but it requires more manual implementation compared to react-beautiful-dnd. Developers need to ensure that their drag-and-drop interfaces are accessible by following best practices and using the provided APIs to manage keyboard interactions and aria attributes.

  • sortablejs:

    sortablejs provides basic accessibility features, but it is up to the developer to ensure that sortable elements are fully accessible. The library does not provide built-in keyboard navigation or screen reader support, so additional work is needed to make it compliant with accessibility standards.

  • react-beautiful-dnd:

    react-beautiful-dnd places a strong emphasis on accessibility, providing keyboard navigation and screen reader support out of the box. It follows WAI-ARIA guidelines to ensure that drag-and-drop interactions are accessible to all users, including those with disabilities.

  • react-sortable-hoc:

    react-sortable-hoc provides good accessibility for sortable lists, but like react-dnd, it requires developers to implement some accessibility features manually. The library encourages best practices for accessibility, but it is not as comprehensive as react-beautiful-dnd in this regard.

Ease of Use: Code Examples

  • react-draggable:

    react-draggable is easy to use for simple dragging functionality. Its API is straightforward, and it requires minimal setup to make elements draggable. The documentation is clear, making it easy for developers to understand how to use the library quickly.

  • react-dnd:

    react-dnd has a steeper learning curve due to its flexibility and customization options. It requires a good understanding of the underlying concepts of drag-and-drop to use effectively. However, the documentation is comprehensive, and there are many examples available to help developers get started.

  • sortablejs:

    sortablejs is lightweight and easy to integrate into projects. Its simple API and minimal setup requirements make it accessible for developers. The documentation is well-structured, providing examples that help users understand how to implement sortable functionality quickly.

  • react-beautiful-dnd:

    react-beautiful-dnd provides a simple and intuitive API for implementing drag-and-drop functionality. Its focus on accessibility and visual feedback makes it easy for developers to create user-friendly interfaces with minimal effort. The library’s documentation is thorough, providing clear examples and guidelines for implementation.

  • react-sortable-hoc:

    react-sortable-hoc is user-friendly for creating sortable lists. Its higher-order component approach simplifies the implementation of sortable functionality, and the documentation provides clear examples to guide developers through the process.

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

    Choose react-draggable if you need a lightweight library for making individual elements draggable. It is perfect for applications that require simple dragging functionality without the overhead of a full drag-and-drop solution.

  • react-dnd:

    Choose react-dnd if you need a highly customizable and flexible drag-and-drop solution that supports complex interactions, including nested drag-and-drop, drag previews, and drop targets. It is suitable for applications that require fine-grained control over the drag-and-drop behavior and are willing to invest time in setting it up.

  • sortablejs:

    Choose sortablejs if you need a fast and lightweight library for creating sortable lists and grids with support for drag-and-drop, drag-and-sort, and multi-sort. It is highly performant and can be easily integrated into React applications, making it a great choice for projects that require minimal dependencies and high efficiency.

  • react-beautiful-dnd:

    Choose react-beautiful-dnd if you need a simple, accessible, and visually appealing drag-and-drop solution for lists and grids. It is ideal for applications that require a straightforward implementation with good support for keyboard navigation and screen readers.

  • react-sortable-hoc:

    Choose react-sortable-hoc if you need to create sortable lists and grids with minimal setup. It is a higher-order component-based library that allows for easy implementation of sortable functionality while maintaining good performance and accessibility.

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,

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

License

MIT