React draggable component

Last update: Aug 5, 2022

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 . At the .DraggableCore property is . Here's how to use it:

// ES6
import Draggable from 'react-draggable'; // The default
import {DraggableCore} from 'react-draggable'; // 
import Draggable, {DraggableCore} from 'react-draggable'; // Both at the same time

// CommonJS
let Draggable = require('react-draggable');
let DraggableCore = Draggable.DraggableCore;

A 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 . Use an intermediate wrapper (...) 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 component transparently adds draggability to its children.

Note: Only a single child is allowed or an Error will be thrown.

For the 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.

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  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 (
//     
//       
Example Target
// // ); // } // // 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. // // Thanks to react-transition-group for the inspiration. // // `nodeRef` is also available on . 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

is a 'batteries-included' component that manages its own state. If you want to completely control the lifecycle of the component, use .

For some users, they may want the nice state management that provides, but occasionally want to programmatically reposition their components. 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 will ignore its internal state and use the provided position instead. Alternatively, you can seed the position using defaultPosition. Technically, since 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 will operate like a completely static component.

For users that require absolute control, a element is available. This is useful as an abstraction over touch and mouse events, but with full control. has no internal state.

See React-Resizable and React-Grid-Layout for some usage examples.

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

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. 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 .

Drag callbacks (onStart, onDrag, onStop) are called with the same arguments as .


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

GitHub

https://github.com/react-grid-layout/react-draggable
Comments
  • 1. Add `offsetParent` prop for alternative offset calculations

    Allows nodes to use the body as origin instead of the parent. This is useful, when the parent's position is changing. When used, resolves #170

    This issue was introduced by a398097ebcc2cbb4df5582a8a3f42f51d21745a0

    please :eyes:

    Reviewed by aeneasr at 2016-07-17 16:45
  • 2. Issues with TypeScript

    Hi, I'm working with TypeScript and installed react-draggable. As it is said in the doc touse the <Draggable /> component I need to import as default:

    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
    

    But when I try to import it:

    // myComponent.tsx
    import Draggable from 'react-draggable';
    

    I get the Module "react-draggable" has no default export. error. Doing:

    import * as Draggable from 'react-draggable';
    

    brings me the <Draggable /> component but in TypeScript syntaxis * as also brings all definitions and typings so I can't use it as a component (error: JSX element type 'Draggable' does not have any construct or call signatures.)

    I only can use it is:

    const Draggable: any = require('react-draggable');
    

    but it's weird since this package already gives typings.

    I'm using typescript 2.3.2 and awesome-typescript-loader 3.1.3. Anyone has encountered this issue? PD: Big thanks to give typings. This is an awesome package!

    Reviewed by crsanti at 2017-04-30 20:44
  • 3. Detecting click vs drag

    I have a use-case in which the draggable element can either be dragged around or clicked to begin editing. Is there a way to detect a single click versus a drag motion?

    Reviewed by robzolkos at 2015-04-18 00:04
  • 4. Added support for custom dragging and dragged class names

    Nifty library! Thanks for creating it. :)

    I noticed that className can be used to specify a custom class (eg for CSS modules) but there is no way to specify a custom is-dragging or is-dragged class. This PR adds that functionality (and tests).

    Note that npm test is broken in master (and won't pass until PR #176 is merged).

    Note that npm run lint also fails in master:

    # FIXME this is usually global
    flow check
    .flowconfig:16 Unsupported option: "esproposal.class_instance_fields"
    make: *** [lint] Error 4
    
    Reviewed by bvaughn at 2016-07-19 05:44
  • 5. Dragging SVG elements in IE (any version)

    At the moment I don't have a jsfiddle setup, but it appears that the dragging of SVG elements has no effect in any version of Internet Explorer. I can't think of any obvious reason why this would be because translate works just fine in IE on SVG. It seems to have something to do with the onDrag event listeners.

    Reviewed by psaia at 2015-08-28 19:44
  • 6. ie11 support

    Hi, is IE11 supported with react-draggable? I couldn't get the demo page to work when using IE11 on a windows 7 vm so I'm not sure if the demo page is just pointing to old code or if this is a general issue with react-draggable.

    When dragging I saw "SCRIPT5007: Unable to get property '0' of undefined or null reference File: react-draggable.min.js, Line: 1, Column: 1805"

    Reviewed by dalehille at 2015-04-30 14:17
  • 7. Make window & document references iframe-aware

    This PR uses the DOM element’s ownerDocument rather than the global document or window to make react-draggable work across iframes. In our use case, we have an app being rendered into an iframe with React Frame Component, so the DOM elements are in a separate document from the document where the React elements are being executed.

    I chose to replace the instanceOf Node check with a simple duck-typing check (https://github.com/mzabriskie/react-draggable/compare/master...Brandcast:iframe?expand=1#diff-9f4a38358e68eff5cf48eda850801a7aL190), which could be adapted to whatever type of conditional. It would even do the same check, but to work across iframes, it would need to first find the window object relative to e.target. Let me know if you want me to change or update that.

    Reviewed by acusti at 2016-07-18 20:53
  • 8. Please, use translate3d instead of translate

    I'm using this on a mobile app, translate is very slow as it don't make use of the GPU, you can just make a 3d option available, I'm forking it just for this. This is a great plugin, it will fit my needs with this option.

    Reviewed by ezsper at 2015-08-25 01:18
  • 9. moveOnStartChange causes unnecessary state updates

    I'm using react-draggable in my application to scroll an item in a viewport (i.e. dragging the background scrolls the view), and also for custom scrollbars around the viewport. Needless to say, I needed to use the moveOnStartChange attribute to keep these two manners of scrolling the same viewport consistent. I found, however, that there was some really buggy behavior in react-draggable, and it stemmed from the fact that componentWillReceiveProps triggers too often.

    If you declare your component like this:

    <Draggable start={{x: 0, y: 0}}>...</Draggable>
    

    then every time the render() method is called, the componentWillReceiveProps method is called because, technically, a new object is being passed as the 'start' property.

    The solution I have come up with is to change lines 471-473 in the componentWillReceiveProps method to:

    if (newProps.moveOnStartChange && newProps.start &&
        (newProps.start.x !== this.props.start.x || newProps.start.y !== this.props.start.y))
    {
        this.setState(this.getInitialState(newProps));
    }
    

    Thoughts?

    Reviewed by jmuerle at 2015-07-14 03:33
  • 10. adding positionOffset prop to

    Hey @STRML, here is my first pass at allowing initial position to be a string percent. It is essentially using the same code as before but does not modify the defaultPosition prop in any way and instead adds a new initialPosition prop.

    I think this is working as is. We should probably add a few more tests to be sure that the drag callbacks that broke last time aren't breaking this time.

    connects https://github.com/mzabriskie/react-draggable/issues/391

    Reviewed by tnrich at 2019-03-08 23:40
  • 11. Unmount after drag causes "setState on unmounted component" error

    Draggable component seems to trigger an error after it is unmounted as the result of an onStop handler.

    Specifically:

    Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
      in Draggable (created by App)
    

    It seems similar to #130.

    I've made a simple repro of the issue with the latest version that you can find here.

    It only seems to happen once, and any following unmounts, even on other instances of the component, do not trigger the error.

    Reviewed by Tenga at 2019-02-25 12:28
  • 12. build(deps): bump terser from 5.13.0 to 5.14.2

    Bumps terser from 5.13.0 to 5.14.2.

    Changelog

    Sourced from terser's changelog.

    v5.14.2

    • Security fix for RegExps that should not be evaluated (regexp DDOS)
    • Source maps improvements (#1211)
    • Performance improvements in long property access evaluation (#1213)

    v5.14.1

    • keep_numbers option added to TypeScript defs (#1208)
    • Fixed parsing of nested template strings (#1204)

    v5.14.0

    • Switched to @​jridgewell/source-map for sourcemap generation (#1190, #1181)
    • Fixed source maps with non-terminated segments (#1106)
    • Enabled typescript types to be imported from the package (#1194)
    • Extra DOM props have been added (#1191)
    • Delete the AST while generating code, as a means to save RAM

    v5.13.1

    • Removed self-assignments (varname=varname) (closes #1081)
    • Separated inlining code (for inlining things into references, or removing IIFEs)
    • Allow multiple identifiers with the same name in var destructuring (eg var { a, a } = x) (#1176)
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    Reviewed by dependabot[bot] at 2022-07-21 02:58
  • 13. Can't use underlying element on mobile

    Hi, I use this Draggable to drag something like a caption, it has an editable span. I want to be able both to drag on touch (even when on top of editable span) and to enter text and place text caret where I touched (like in the default). I think this works on desktop but because of preventDefault if touchstart/move/end it doesn't work on touch devices (mobile). I know you implemented this to stop some scroll, but maybe user can implement it or you can make it optional, or something like that... Can you fix this, please or do you maybe have a workaround for me? Thank you, I really like your component it is really nice and simple to use!

    Reviewed by MiljkovicMarko at 2022-06-30 18:41
  • 14. Draggable not adhering to correct grid on different scales

    I am using the grid and scale together in a component. However, when I want zoom in (so the scale prop changes), the component does not adhere to the grid for scale 1 but for the current scale. For example, I am using [25, 25] as grid and the scale changes as I zoom in and out. At scale=1, it works perfectly. At scale=0.5, it will use a grid of [12.5, 12.5] with respect to scale=1. At scale=2, it will use a grid of [50, 50] with respect to scale=1.

    I think that the draggable component should adhere to the grid at scale=1 at all scales. So, at scale=0.5, it should move 50 pixels, instead of 25, since that would account for the change in scale. This could be implemented by setting the grid to [x * scale, y * scale], instead of [x, y].

    Reviewed by cristianpjensen at 2022-06-30 00:04
  • 15. z-ndex

    Hello everyone.

    I have several draggable elements on the page. I need to change the z-index in it by clicking on an element so that it appears on top. To do this, I passed styles to the div inside the DND wrapper, but it doesn't help.

    Tell me how I can influence the z-index. Thanks!

    Reviewed by Sergey-Shar at 2022-06-16 11:24
  • 16. in typescript the type notice error: is not assignable to type 'IntrinsicAttributes

    TS2322: Type '{ children: Element[]; list: TagItem[]; setList: Dispatch<SetStateAction<TagItem[]>>; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<ReactSortable> & Pick<Readonly<ReactSortableProps>, never> & InexactPartial<...> & InexactPartial<...>'.   Property 'children' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<ReactSortable> & Pick<Readonly<ReactSortableProps>, never> & InexactPartial<...> & InexactPartial<...>'.

    my code:

    type TagItem = { id: number, name: string, parent_id: number }

      const [tags, setTags] = useState<TagItem[]>([])
    
      <ReactSortable list={tags} setList={setTags}>
       {
                    tags.map(tag => <TagItem key={tag.id} tag={tag} />)
       }
     </ReactSortable>
    
    Reviewed by seanock at 2022-05-26 10:03
Draggable and Resizable component running at 60FPS using React Native Reanimated v2
Draggable and Resizable component running at 60FPS using React Native Reanimated v2

reanimated-drag-resize Draggable and Resizable React Native Component running at 60FPS using React Native Reanimated v2 Main Dependencies react-native

Jun 23, 2022
React component to create graphic user interface with: - draggable nodes with ports and edges on a directed graph editor. - extensibility to customize the widgets or behaviors. - accessbility and testability support

Work in progress react-flow-editor Overview React component to create graphic user interface with: draggable nodes with ports and edges on a directed

Aug 1, 2022
React component for a list of draggable collapsible items
React component for a list of draggable collapsible items

react-draggable-list This component lets you make a user re-orderable list that animates nicely so that the user can easily move large items: The abov

Jul 27, 2022
A simple draggable list component for React
A simple draggable list component for React

react-drag-listview React drag list component. install Example Drag Rows Simple dragging demo Dragging Ant-Design table Dragging Ant-Design table widt

Jul 14, 2022
A simple component for making elements draggable

React Draggable Component A simple component for making elements draggable.

Jul 15, 2022
A draggable and resizable grid layout with responsive breakpoints, for React.
A draggable and resizable grid layout with responsive breakpoints, for React.

React-Grid-Layout React-Grid-Layout is a grid layout system much like Packery or Gridster, for React.

Aug 4, 2022
Draggable tree for react.

react-draggable-tree Draggable tree for react. installation npm install -S @jswork/react-draggable-tree properties Name Type Required Default Descript

Mar 25, 2021
Draggable, Smart menu for react

Features ⚡ Configurable and smart floating menu for react ⚙️ Comes with a lot of options to customize the behavior of the menu ?? Auto detects edges o

Jul 30, 2022
:sparkles: A sortable and resizable pane component for React.
:sparkles: A sortable and resizable pane component for React.

Sortable and resizable pane component for react. Table of Contents Screenshot Live Demo Storybook CodeSandbox Install Usage uncontrolled controlled Pr

Jul 30, 2022
Unopinionated dropdown component for react.
Unopinionated dropdown component for react.

Unopinionated dropdown component for react.

Jul 11, 2022
"Drag to resize" (sizing) as React Component.

react-drag-sizing "Drag to resize" (sizing) as React Component Rewritten with TS & React-hooks Polyfill workaround with React < 16.8 Support both mous

Jul 27, 2022
A rectangle react component which can be resized and rotated

React-resizable-rotatable-draggable-rectangle A react widget that can be resized and rotated via a handler. Installation npm install --save react-resi

Jul 19, 2022
React component which implements scrolling via holding the mouse button or touch
React component which implements scrolling via holding the mouse button or touch

React Indiana Drag Scroll Implements scroll on drag Examples / Sandbox Welcome to journey! Try it yourself! Go to demo website. Install npm install --

Aug 1, 2022
🦋 Component for building file fields - from basic file inputs to drag and drop image galleries.
🦋 Component for building file fields - from basic file inputs to drag and drop image galleries.

?? react-butterfiles A small component for building file upload fields of any type, for example a simple file upload button or an image gallery field

Jun 6, 2022
Beautiful and accessible drag and drop for lists with React
Beautiful and accessible drag and drop for lists with React

react-beautiful-dnd (rbd) Beautiful and accessible drag and drop for lists with React Play with this example if you want! Core characteristics Beautif

Aug 1, 2022
Drag and Drop for React
Drag and Drop for React

React DnD Drag and Drop for React. See the docs, tutorials and examples on the website: http://react-dnd.github.io/react-dnd/ See the changelog on the

Jul 31, 2022
Simple HTML5 drag-drop zone with React.js.

react-dropzone Simple React hook to create a HTML5-compliant drag'n'drop zone for files. Documentation and examples at https://react-dropzone.js.org.

Jul 31, 2022
🔀 Drag and drop for your React lists and tables. Accessible. Tiny.
🔀 Drag and drop for your React lists and tables. Accessible. Tiny.

react-movable See all the other examples and their source code! Installation yarn add react-movable Usage import * as React from 'react'; import { Li

Aug 4, 2022
Drag and Drop for React
Drag and Drop for React

React DnD Drag and Drop for React. See the docs, tutorials and examples on the website: http://react-dnd.github.io/react-dnd/ See the changelog on the

Aug 6, 2022