react-draggable vs react-intersection-observer vs react-dnd vs react-use vs react-spring vs react-swipeable vs react-move vs react-use-gesture
React Animation and Gesture Libraries
react-draggablereact-intersection-observerreact-dndreact-usereact-springreact-swipeablereact-movereact-use-gestureSimilar Packages:
React Animation and Gesture Libraries

React Animation and Gesture Libraries are specialized tools designed to enhance user interfaces in React applications by providing smooth animations, transitions, and gesture-based interactions. These libraries offer pre-built components and hooks that simplify the implementation of complex animations, making them more accessible to developers. They can significantly improve the user experience by adding visual flair, providing feedback on interactions, and making applications feel more dynamic and responsive. Examples include react-spring for physics-based animations, react-dnd for drag-and-drop functionality, and react-intersection-observer for detecting when elements enter or leave the viewport.

Npm Package Weekly Downloads Trend
3 Years
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
react-draggable3,833,8949,257243 kB2446 months agoMIT
react-intersection-observer3,212,7225,501162 kB12 months agoMIT
react-dnd3,009,43121,617231 kB475-MIT
react-use2,570,57343,825454 kB645a year agoUnlicense
react-spring886,15129,0038.36 kB1343 months agoMIT
react-swipeable677,7572,11187.5 kB31a year agoMIT
react-move06,584-285 years agoMIT
react-use-gesture09,534-495 years agoMIT
Feature Comparison: react-draggable vs react-intersection-observer vs react-dnd vs react-use vs react-spring vs react-swipeable vs react-move vs react-use-gesture

Drag-and-Drop Functionality

  • react-draggable:

    react-draggable offers simple drag-and-drop functionality with minimal setup. It allows elements to be dragged within a defined boundary, but it does not support complex interactions like nested drag-and-drop or multiple drop targets. It is best for projects that need basic draggable elements without extensive customization.

  • react-dnd:

    react-dnd provides a comprehensive drag-and-drop API that supports complex interactions, including nested drag-and-drop, custom drag previews, and multiple drop targets. It is highly customizable and allows developers to define their own drag-and-drop logic, making it suitable for applications that require advanced functionality.

Animation Capabilities

  • react-spring:

    react-spring is a physics-based animation library that provides a more dynamic and natural approach to animations. It supports both simple and complex animations, including gesture-based animations, and allows for greater customization and control over the animation behavior. It is suitable for applications that require high-performance, fluid animations with a modern API.

  • react-move:

    react-move focuses on animating transitions between different states of a component. It provides a simple API for defining animations based on data changes, making it ideal for visualizing transitions and creating smooth, choreographed animations. It is particularly useful for data-driven animations where the animation is triggered by changes in state or props.

Viewport Detection

  • react-intersection-observer:

    react-intersection-observer provides a simple way to detect when elements enter or leave the viewport. It is useful for implementing lazy loading, infinite scrolling, and triggering animations based on visibility. The library is lightweight and easy to use, making it a great choice for performance-sensitive applications.

  • react-swipeable:

    react-swipeable does not provide viewport detection; instead, it focuses on detecting swipe gestures on touch devices. It is useful for adding touch interactions to components but does not offer any functionality related to viewport visibility.

Gesture Handling

  • react-swipeable:

    react-swipeable specializes in handling swipe gestures. It is lightweight and easy to use, making it perfect for mobile applications that need to respond to swipe interactions. While it is not as feature-rich as react-use-gesture, it is focused and effective for its intended use case.

  • react-use-gesture:

    react-use-gesture provides a simple and intuitive API for handling complex gestures, including drag, pinch, and rotate. It is highly customizable and works well with react-spring for creating gesture-driven animations. This library is ideal for applications that require advanced gesture recognition and want to create more interactive and engaging user experiences.

Reusability and Modularity

  • react-dnd:

    react-dnd is designed for building reusable drag-and-drop components, but it does not focus on reusability at the hook level. It provides a set of APIs and components that can be reused across different parts of an application, but it is not as modular as a hook-based library.

  • react-use:

    react-use is a collection of reusable hooks that cover a wide range of use cases, including animations, gestures, and more. It promotes code reusability and modularity, allowing developers to use hooks as needed without having to import a large library.

Ease of Use: Code Examples

  • react-draggable:

    Simple Draggable Component with react-draggable

    import React from 'react';
    import { Draggable } from 'react-draggable';
    
    const DraggableComponent = () => {
      return (
        <Draggable>
          <div style={{ width: '100px', height: '100px', background: 'lightcoral' }}>Drag me</div>
        </Draggable>
      );
    };
    
    const App = () => <DraggableComponent />;
    
    export default App;
    
  • react-intersection-observer:

    Viewport Detection with react-intersection-observer

    import React from 'react';
    import { useInView } from 'react-intersection-observer';
    
    const InViewComponent = () => {
      const { ref, inView } = useInView({ threshold: 0.5 });
    
      return (
        <div ref={ref} style={{ height: '200px', background: inView ? 'lightgreen' : 'lightcoral' }}>
          {inView ? 'In View' : 'Out of View'}
        </div>
      );
    };
    
    const App = () => <InViewComponent />;
    
    export default App;
    
  • react-dnd:

    Basic Drag-and-Drop with react-dnd

    import React from 'react';
    import { DndProvider, useDrag, useDrop } from 'react-dnd';
    import { HTML5Backend } from 'react-dnd-html5-backend';
    
    const ItemType = 'BOX';
    
    const DraggableBox = () => {
      const [{ isDragging }, drag] = useDrag({
        type: ItemType,
        item: { id: 1 },
        collect: (monitor) => ({ isDragging: monitor.isDragging() }),
      });
    
      return <div ref={drag} style={{ opacity: isDragging ? 0.5 : 1 }}>Drag me</div>;
    };
    
    const DropZone = () => {
      const [{ isOver }, drop] = useDrop({
        accept: ItemType,
        drop: () => console.log('Dropped!'),
        collect: (monitor) => ({ isOver: monitor.isOver() }),
      });
    
      return <div ref={drop} style={{ background: isOver ? 'lightblue' : 'lightgray', height: '200px' }}>Drop here</div>;
    };
    
    const App = () => (
      <DndProvider backend={HTML5Backend}>
        <div style={{ display: 'flex', gap: '20px' }}>
          <DraggableBox />
          <DropZone />
        </div>
      </DndProvider>
    );
    
    export default App;
    
  • react-use:

    Reusable Hook Example from react-use

    import React from 'react';
    import { useFetch } from 'react-use';
    
    const FetchComponent = () => {
      const { value, error } = useFetch('https://api.example.com/data');
    
      if (error) return <div>Error: {error.message}</div>;
      if (!value) return <div>Loading...</div>;
    
      return <div>Data: {JSON.stringify(value)}</div>;
    };
    
    const App = () => <FetchComponent />;
    
    export default App;
    
  • react-spring:

    Physics-Based Animation with react-spring

    import React from 'react';
    import { useSpring, animated } from 'react-spring';
    
    const SpringComponent = () => {
      const props = useSpring({ to: { opacity: 1 }, from: { opacity: 0 }, config: { duration: 1000 } });
    
      return <animated.div style={props}>I fade in!</animated.div>;
    };
    
    const App = () => <SpringComponent />;
    
    export default App;
    
  • react-swipeable:

    Swipe Gesture Detection with react-swipeable

    import React from 'react';
    import { useSwipeable } from 'react-swipeable';
    
    const SwipeableComponent = () => {
      const handlers = useSwipeable({
        onSwiped: (eventData) => console.log('Swiped!', eventData),
      });
    
      return <div {...handlers} style={{ width: '100%', height: '200px', background: 'lightblue' }}>Swipe me</div>;
    };
    
    const App = () => <SwipeableComponent />;
    
    export default App;
    
  • react-move:

    Data-Driven Animation with react-move

    import React from 'react';
    import { Motion, spring } from 'react-move';
    
    const AnimatedComponent = () => {
      return (
        <Motion
          default={{ x: 0 }}
          style={{ x: spring(100) }}
        >
          {({ x }) => <div style={{ transform: `translateX(${x}px)` }}>I move!</div>}
        </Motion>
      );
    };
    
    const App = () => <AnimatedComponent />;
    
    export default App;
    
  • react-use-gesture:

    Gesture Handling with react-use-gesture

    import React from 'react';
    import { useDrag } from 'react-use-gesture';
    import { animated } from 'react-spring';
    
    const DraggableComponent = () => {
      const bind = useDrag((state) => {
        console.log(state.offset);
      });
    
      return <animated.div {...bind()} style={{ width: '100px', height: '100px', background: 'lightcoral' }}>Drag me</animated.div>;
    };
    
    const App = () => <DraggableComponent />;
    
    export default App;
    
How to Choose: react-draggable vs react-intersection-observer vs react-dnd vs react-use vs react-spring vs react-swipeable vs react-move vs react-use-gesture
  • react-draggable:

    Select react-draggable if you need a simple and lightweight solution for making elements draggable. It is easy to integrate and requires minimal setup, making it suitable for projects that need basic drag-and-drop functionality without the overhead of a full-featured library. It is perfect for applications that need quick and straightforward draggable components, such as image galleries, sliders, or simple interactive UIs.

  • react-intersection-observer:

    Use react-intersection-observer if you need to detect when elements enter or leave the viewport. This library is useful for implementing lazy loading, infinite scrolling, or triggering animations when elements become visible on the screen. It is lightweight and easy to use, making it a great choice for performance-sensitive applications that need to optimize rendering or load content dynamically based on visibility.

  • react-dnd:

    Choose react-dnd if you need a robust and customizable drag-and-drop solution that supports complex interactions, such as nested drag-and-drop, drag previews, and drop targets. It is ideal for applications that require fine-grained control over the drag-and-drop behavior, such as kanban boards, file upload interfaces, or any application that needs advanced drag-and-drop functionality.

  • react-use:

    Choose react-use if you are looking for a collection of reusable hooks that cover a wide range of use cases, including animations, gestures, and more. It is a great choice for developers who want to leverage hooks to build more modular and reusable components. This library is suitable for projects that want to improve code reusability and reduce duplication by using well-designed hooks for common tasks.

  • react-spring:

    Select react-spring if you are looking for a powerful and flexible animation library that uses physics-based animations to create natural and smooth transitions. It supports both simple and complex animations, including gestures, and is highly customizable. It is suitable for applications that require high-performance animations with a modern API, making it ideal for interactive UIs, animated illustrations, and any project that benefits from fluid, responsive animations.

  • react-swipeable:

    Use react-swipeable if you need to add swipe gestures to your components. This library is lightweight and easy to use, making it perfect for mobile-friendly applications that require touch interactions, such as image sliders, swipeable cards, or any component that needs to respond to swipe gestures. It is ideal for projects that want to enhance touch interactions without adding a lot of complexity.

  • react-move:

    Choose react-move if you want to create smooth, choreographed animations between different states of your components. It provides a simple API for animating properties based on data changes, making it ideal for visualizing data transitions, creating animated charts, or adding fluid animations to your UI. It is particularly useful for applications that require data-driven animations and want to create a more engaging user experience.

  • react-use-gesture:

    Select react-use-gesture if you need a library that provides a simple and intuitive API for handling complex gestures, such as pinch, rotate, and multi-touch interactions. It is highly customizable and works well with react-spring for creating gesture-driven animations. This library is ideal for applications that require advanced gesture recognition and want to create more interactive and engaging user experiences.

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>
VersionCompatibility
4.xReact 16.3+
3.xReact 15-16
2.xReact 0.14 - 15
1.xReact 0.13 - 0.14
0.xReact 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