React wrapper components for smooth-dnd

Overview

react-smooth-dnd

A fast and lightweight drag&drop, sortable library for React with many configuration options covering many d&d scenarios. It uses css transitions for animations so it's hardware accelerated whenever possible.

This library consists wrapper React components over smooth-dnd library.

Show, don't tell !

Demo page

Installation

npm i react-smooth-dnd

Usage

JSX

import React, { Component } from 'react';
import { Container, Draggable } from 'react-smooth-dnd';

class SimpleSortableList extends Component {
  render() {
    return (
      <div>
        <Container onDrop={this.props.onDrop}>
          {this.props.items.map(item => {
            return (
              <Draggable key={item.id}>
                {this.props.renderItem(item)}
              </Draggable>
            );
          })}
        </Container>
      </div>
    );
  }
}

API

Container

Component that contains the draggable elements or components. Each of its children should be wrapped by Draggable component

Props

Property Type Default Description
children Draggable null React children prop. Should be of type Draggable.
orientation string vertical Orientation of the container. Can be horizontal or vertical.
behaviour string move Property to describe weather the dragging item will be moved or copied to target container. If drop-zone is set no draggable will slide when container dragged over. Can be move or copy or drop-zone or contain
groupName string undefined Draggables can be moved between the containers having the same group names. If not set container will not accept drags from outside. This behaviour can be overriden by shouldAcceptDrop function. See below.
lockAxis string undefined Locks the movement axis of the dragging. Possible values are x, y or undefined.
dragHandleSelector string undefined Css selector to test for enabling dragging. If not given item can be grabbed from anywhere in its boundaries.
nonDragAreaSelector string undefined Css selector to prevent dragging. Can be useful when you have form elements or selectable text somewhere inside your draggable item. It has a precedence over dragHandleSelector.
dragBeginDelay number 0 (200 for touch devices) Time in milisecond. Delay to start dragging after item is pressed. Moving cursor before the delay more than 5px will cancel dragging.
animationDuration number 250 Animation duration in milisecond. To be consistent this animation duration will be applied to both drop and reorder animations.
autoScrollEnabled boolean true First scrollable parent will scroll automatically if dragging item is close to boundaries.
dragClass string undefined Class to be added to the ghost item being dragged. The class will be added after it's added to the DOM so any transition in the class will be applied as intended.
dropClass string undefined Class to be added to the ghost item just before the drop animation begins.
removeOnDropOut boolean undefined When set true onDrop will be called with a removedIndex if you drop element out of any relevant container
dropPlaceholder boolean,object undefined Options for drop placeholder. className, animationDuration, showOnTop
onDragStart function undefined See descriptions below
onDragEnd function undefined See descriptions below
onDropReady function undefined See descriptions below
onDrop function undefined See descriptions below
getChildPayload function undefined See descriptions below
shouldAnimateDrop function undefined See descriptions below
shouldAcceptDrop function undefined See descriptions below
onDragEnter function undefined See descriptions below
onDragLeave function undefined See descriptions below
getGhostParent function undefined See descriptions below
render function undefined See descriptions below

onDragStart

The function to be called by all container when drag start.

function onDragStart({isSource, payload, willAcceptDrop}) {
  ...
}

Parameters

  • isSource : boolean : true if it is called by the container which drag starts from otherwise false.
  • payload : object : the payload object that is returned by getChildPayload function. It will be undefined in case getChildPayload is not set.
  • willAcceptDrop : boolean : true if the dragged item can be dropped into the container, otherwise false.

onDragEnd

The function to be called by all container when drag ends. Called before onDrop function

function onDragEnd({isSource, payload, willAcceptDrop}) {
  ...
}

Parameters

  • isSource : boolean : true if it is called by the container which drag starts from, otherwise false.
  • payload : object : the payload object that is returned by getChildPayload function. It will be undefined in case getChildPayload is not set.
  • willAcceptDrop : boolean : true if the dragged item can be dropped into the container, otherwise false.

onDropReady

The function to be called by the container which is being drag over, when the index of possible drop position changed in container. Basically it is called each time the draggables in a container slides for opening a space for dragged item. dropResult is the only parameter passed to the function which contains the following properties.

function onDropReady(dropResult) {
  const { removedIndex, addedIndex, payload, element } = dropResult;
  ...
}

Parameters

  • dropResult : object
    • removedIndex : number : index of the removed children. Will be null if no item is removed.
    • addedIndex : number : index to add droppped item. Will be null if no item is added.
    • payload : object : the payload object retrieved by calling getChildPayload function.
    • element : DOMElement : the DOM element that is moved

onDrop

The function to be called by any relevant container when drop is over. (After drop animation ends). Source container and any container that could accept drop is considered relevant. dropResult is the only parameter passed to the function which contains the following properties.

function onDrop(dropResult) {
  const { removedIndex, addedIndex, payload, element } = dropResult;
  ...
}

Parameters

  • dropResult : object
    • removedIndex : number : index of the removed children. Will be null if no item is removed.
    • addedIndex : number : index to add droppped item. Will be null if no item is added.
    • payload : object : the payload object retrieved by calling getChildPayload function.
    • element : DOMElement : the DOM element that is moved

getChildPayload

The function to be called to get the payload object to be passed onDrop function.

function getChildPayload(index) {
  return {
    ...
  }
}

Parameters

  • index : number : index of the child item

Returns

  • payload : object

shouldAnimateDrop

The function to be called by the target container to which the dragged item will be droppped. Sometimes dragged item's dimensions are not suitable with the target container and dropping animation can be wierd. So it can be disabled by returning false. If not set drop animations are enabled.

function shouldAnimateDrop(sourceContainerOptions, payload) {
  return false;
}

Parameters

  • sourceContainerOptions : object : options of the source container. (parent container of the dragged item)
  • payload : object : the payload object retrieved by calling getChildPayload function.

Returns

  • boolean : true / false

shouldAcceptDrop

The function to be called by all containers before drag starts to determine the containers to which the drop is possible. Setting this function will override the groupName property and only the return value of this function will be taken into account.

function shouldAcceptDrop(sourceContainerOptions, payload) {
  return true;
}

Parameters

  • sourceContainerOptions : object : options of the source container. (parent container of the dragged item)
  • payload : object : the payload object retrieved by calling getChildPayload function.

Returns

  • boolean : true / false

onDragEnter

The function to be called by the relevant container whenever a dragged item enters its boundaries while dragging.

function onDragEnter() {
  ...
}

onDragLeave

The function to be called by the relevant container whenever a dragged item leaves its boundaries while dragging.

function onDragLeave() {
  ...
}

getGhostParent

The function to be called to get the element that the dragged ghost will be appended. Default parent element is the container itself. The ghost element is positioned as 'fixed' and appended to given parent element. But if any anchestor of container has a transform property, ghost element will be positioned relative to that element which breaks the calculations. Thats why if you have any transformed parent element of Containers you should set this property so that it returns any element that has not transformed parent element.

function getGhostParent() {
  // i.e return document.body;
}

render

By default Container uses a div element for component root. You can define what to render as root element by using render function. If render function is set, children prop of Container will be ignored and return value of the render will be used to render draggables.

function render(ref) {
  // return ReactElement
}

Parameters

  • ref : object : React reference object created by React.createRef()

Returns

  • React Element
<Container render={(ref) => {
  return (
    <ul ref={ref}>
      ...place your <Draggable/> components here
    </ul>
  )
}}/>

Draggable

Wrapper component for Container's children. Every draggable element should be wrapped with Draggable component.

Make sure to set unique key to Draggable especially when it contains other Container components

Props

Property Type Default Description
render function undefined See descriptions below

render

By default Draggable uses a div element for component root. You can define what to render as root element by using render function. If render function is set, children prop of Draggable will be ignored and return value of the render will be used to render draggable.

<Draggable render={() => {
  return (
    <li>
      ...
    </li>
  )
}}/>

Parameters

  • ref : object : React reference object created by React.createRef()

Returns

  • React Element
Comments
  • Not able to drop properly in side by side container (Attached video link)

    Not able to drop properly in side by side container (Attached video link)

    @kutlugsahin I have two containers side by side with a width 50% as columns with the assigned array with drop accept but not able to drop properly in the container but if I move element vertically from bottom to top or top to bottom then I can drop in that container but if I move element from left to right over the row then not getting proper container area to drop.

    Please refer below video link: https://www.loom.com/share/2b7ce4a5e16e4793b8ddecbfe939c3d6

    opened by codergkd 6
  • Duplicated onDrop call

    Duplicated onDrop call

    Hello,

    I've hit a condition where if I drag into another container of the same groupName, onDrop is called on two containers at once, which makes my app add the object to it. I have a video demo-ing the issue: https://cl.ly/6d371064c0e6

    Did anyone ever hit this?

    Thanks in advance,

    • rafael
    opened by objectivecosta 4
  • Grid layout & information about drop target

    Grid layout & information about drop target

    Hi @kutlugsahin, thank you for open-sourcing this - this looks great! Two quick questions -

    1. Is the Grid layout supported for Drag/Drop (or atleast on a Flexbox in say 2 rows)?

    2. I have a usecase where on drop, I'd like to distinguish between if the item was dropped between two items or on top of an item. So, I am wondering if you foresee the API supporting that, and/or boundaries within a target (that helps determine intent of drop - like middle 50% is considered dropping on the target)?

    question 
    opened by oyeanuj 4
  • I am trying for editor

    I am trying for editor

    When I drag the element from copy behavior then dropped element should be HTML element and I have to change the content of each dropped elements and store updated content in an array of objects with drag n drop support? Please reply?

    opened by codergkd 3
  • Multiple Containers all with copy behavior

    Multiple Containers all with copy behavior

    Hi,

    I'd like to have multiple containers, and I want to copy draggables from any container to any other container. I have set them all to the same groupName and behavior="copy", however then I can not drag from one to the other. Is this a bug?

    Thanks Max

    opened by maxsalven 3
  • Context API

    Context API

    Is there a bug using the Context API? I have done an example in CodeSandBox: https://codesandbox.io/s/jz1j2row15

    When moving the Draggable it starts mixing up things, even though they all have a key prop. Besides that, when using create-react-app and using the Context API, after moving around the Draggable it throws an error saying it can read the id of the element, which is being used by the key prop.

    bug 
    opened by vititu 3
  • Container that is initially empty is not animated

    Container that is initially empty is not animated

    Thanks for this awesome library. The API is well-written and I am using it here: react-trello

    I have one question about drag-n-drop to containers that are initially empty. When a draggable component is dropped in the container, a new wrapper is created with the following structure, but however the animated class is not added, so the container does not animate to create placeholder or move existing elements.

    <div class="smooth-dnd-draggable-wrapper">
    ...
    </div>
    

    In the below illustration, the blocked lane is initially an empty container, note that when draggable cards are added to it, it does not animate:

    may-06-2018 12-29-39

    Let me know If I am missing something! You can check the code in the repo too if needed.

    opened by rcdexta 3
  • Uncaught TypeError: Illegal invocation

    Uncaught TypeError: Illegal invocation

    We're getting a Uncaught TypeError: Illegal invocation error when using react-smooth-dnd with @loadable/component.

    Specifically, we're trying to import a component that uses react-smooth-dnd dynamically. As the page loads, the error is thrown. The full stack trace is as below:

    loadable.esm.js:269 Uncaught TypeError: Illegal invocation
        at Node.get (VM217 8.js:97747)
        at VM217 8.js:97747
        at VM217 8.js:97747
        at Object../node_modules/smooth-dnd/dist/index.js (VM217 8.js:97747)
        at __webpack_require__ (VM210 app.js:64)
        at VM217 8.js:89812
        at Object../node_modules/react-smooth-dnd/dist/index.js (VM217 8.js:89812)
        at __webpack_require__ (VM210 app.js:64)
        at Module../src/components/Sunspot/index.js (VM218 10.js:13301)
        at __webpack_require__ (VM210 app.js:64)
    

    Googling on the issue seems to point towards a loss of context or an undefined global variable after webpack builds.

    Has anyone faced similar issues? Any help would be much appreciated. We burned a weekend trying to solve this single issue.

    Update: Wanted to add a note that the application works when running via webpack-dev-server directly, but throws the error above after webpack builds it.

    opened by ahmadsholehin 2
  • Is there any way to prevent coming drag & drop if container has more than 3 draggable items?

    Is there any way to prevent coming drag & drop if container has more than 3 draggable items?

    I am implementing React drag and drop using this library and I have one problem. I have several containers in the app and I am going to prevent coming drag & drop(though I can move existing draggable into another container) if that container has more than 3 draggables inside. 🤔 It would be nice if I can solve this issue soon. Thanks. 👍

    opened by bracano45 2
  • Could not find a declaration file for module 'react-smooth-dnd'.

    Could not find a declaration file for module 'react-smooth-dnd'.

    Hi guys. When I am try to import the libary I get this:

    Could not find a declaration file for module 'react-smooth-dnd'.

    Anyone could explain to me what problem is it and how to fix it? Thanks in advance

    opened by rogix 2
  • User-defined drag cursor reverts to default cursor when dragging

    User-defined drag cursor reverts to default cursor when dragging

    The drag handle cursor style appears on hover, but when dragging, it changes back to the default arrow cursor. Example: https://kutlugsahin.github.io/smooth-dnd-demo/

    opened by brietsparks 2
  • Performance issue

    Performance issue

    When i used the library for kanban board i got performance issue when data 500+ elements, so i used "react-virtuoso" and bass ref from "render" while ref.current = null the react-virtuoso returned null or undefined but render was broken. could we add loader while ref is null?!

    opened by rwaidaAlmehanni 0
  • Please fix

    Please fix "Property 'children' does not exist on type 'IntrinsicAttributes'"

    Hi! 👋

    Firstly, thanks for your work on this project! 🙂

    Today I used patch-package to patch [email protected] for the project I'm working on.

    Here is the diff that solved my problem:

    diff --git a/node_modules/react-smooth-dnd/dist/src/Container.d.ts b/node_modules/react-smooth-dnd/dist/src/Container.d.ts
    index cdd0c03..211eb1c 100644
    --- a/node_modules/react-smooth-dnd/dist/src/Container.d.ts
    +++ b/node_modules/react-smooth-dnd/dist/src/Container.d.ts
    @@ -1,11 +1,11 @@
    -import React, { Component, CSSProperties } from 'react';
    +import React, { Component, CSSProperties, PropsWithChildren } from 'react';
     import PropTypes from 'prop-types';
     import { ContainerOptions, SmoothDnD } from 'smooth-dnd';
     interface ContainerProps extends ContainerOptions {
         render?: (rootRef: React.RefObject<any>) => React.ReactElement;
         style?: CSSProperties;
     }
    -declare class Container extends Component<ContainerProps> {
    +declare class Container extends Component<PropsWithChildren<ContainerProps>> {
         static propTypes: {
             behaviour: PropTypes.Requireable<string>;
             groupName: PropTypes.Requireable<string>;
    diff --git a/node_modules/react-smooth-dnd/dist/src/Draggable.d.ts b/node_modules/react-smooth-dnd/dist/src/Draggable.d.ts
    index 7ddbb5b..9783d0f 100644
    --- a/node_modules/react-smooth-dnd/dist/src/Draggable.d.ts
    +++ b/node_modules/react-smooth-dnd/dist/src/Draggable.d.ts
    @@ -1,10 +1,10 @@
    -import React, { Component } from 'react';
    +import React, { Component, PropsWithChildren } from 'react';
     import PropTypes from 'prop-types';
     export interface DraggableProps {
         render?: () => React.ReactElement;
         className?: string;
     }
    -declare class Draggable extends Component<DraggableProps> {
    +declare class Draggable extends Component<PropsWithChildren<DraggableProps>> {
         static propsTypes: {
             render: PropTypes.Requireable<(...args: any[]) => any>;
             className: PropTypes.Requireable<string>;
    

    This issue body was partially generated by patch-package.

    opened by cothvbdnnn 0
  • Question about getContainerOptions

    Question about getContainerOptions

    Hello,

    First of all, thank you so much for your work on this project. It's been immensely helpful for our team.

    We ran into issues using this package directly because we are running React 18.2 and we ran into dependency conflicts with the React 16 version of this repo. Therefore, we've decided to port the components into our own codebase and we'll personally maintain them for our own project. This is fine for us, because the codebase is small.

    I did want to make sure that I'm doing my due diligence in understanding how this package functions and I just had a question about this bit of code in Container.tsx:

       ...
          if (typeof prop === 'function') {
            result[optionName] = (...params: any[]) => {
              return (this.props[optionName] as Function)(...params);
            }
       ...
    

    I have never seen this pattern before. Would it be possible to explain what is going regarding function props here? Why is this necessary? Is it because React handles Object/Array/Function prop updates as Pass-by-Reference instead of Pass-by-Value?

    opened by juliarvalenti 0
  • Flickering issue

    Flickering issue

    Hey guys, I've just started using this library, and I've noticed that for some reason when I drop a card into the next column all the cards under the dropped location flicker. All my components are super well optimised, thus not re-rendering, except for the dropped one. Any ideas what could cause this? Thanks

    Demo video:

    https://user-images.githubusercontent.com/71137/189447966-806fe10f-673a-4793-85e0-cdb37c543ef8.mov

    CC: @kutlugsahin

    opened by synapse 0
  • horizontal scroll not working when using infinite scroll

    horizontal scroll not working when using infinite scroll

    I have this usecase that there are several columns (containers) and inside them are draggable cards. each column must have a fixed height and overflow-y: auto because cards' data is coming from an external API and may be too many, so I have to implement infinite scroll inside each column.

    so the problem is when I use overflow-y: auto inside each column (the div.card-container or div.smooth-dnd-container.vertical no difference), and then try to drag a card from column 1 to column 8 for example, the entire container is not scrolling by itself. I've used the first example in the documentation and tweaked it a little bit to show you the problem: codesandbox demo

    screen-recorder-wed-jul-27-2022-10-40-43.webm

    opened by pedram6195 1
Owner
Kutlu Sahin
JavaScript Developer
Kutlu Sahin
Addon for the 'react-beautiful-dnd' that adds natural dragging animation

Info Addon for the react-beautiful-dnd that adds natural dragging animation

Dmytro Lytvynenko 38 Nov 16, 2022
Package-React-Dnd example

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Nidhi Verma 1 Nov 21, 2021
Light React Drag & Drop files and images library styled by styled-components

Light React Drag & Drop files and images library styled by styled-components

null 143 Dec 28, 2022
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

Atlassian 28.9k Dec 31, 2022
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

React DnD 18.7k Jan 7, 2023
React draggable component

React-Draggable A simple component for making elements draggable. <Draggable> <div>I can now be moved around!</div> </Draggable> Demo Changelog Vers

Samuel Reed 8.1k Jan 1, 2023
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.

null 9.4k Jan 2, 2023
🔀 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

Vojtech Miksu 1.3k Dec 30, 2022
: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

bokuweb 616 Dec 19, 2022
Unopinionated dropdown component for react.

Unopinionated dropdown component for react.

Akinwunmi Aguda 7 Jul 11, 2022
React draggable component

A simple component for making elements draggable.

RGL 8.1k Jan 8, 2023
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.

RGL 16.9k Jan 2, 2023
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

React DnD 18.7k Jan 6, 2023
A modern, lightweight, performant, accessible and extensible drag & drop toolkit for React.

A modern, lightweight, performant, accessible and extensible drag & drop toolkit for React.

Claudéric Demers 6.5k Jan 7, 2023
Drag and Drop for React

Drag and Drop for React

React DnD 18.7k Jan 4, 2023
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

Fateh Farooqui 39 Dec 28, 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

Microsoft 102 Dec 29, 2022
React Drag and Drop file input

React Drag and Drop file input

Tran Anh Tuat 45 Dec 30, 2022
a dragger layout system with React style .

特别声明 由于本人正在忙其他的事情,dragact 已经暂停维护了。请不要使用 dragact(出了问题我实在没精力帮您解决,实在抱歉 最后,我推荐的替换是: https://github.com/STRML/react-grid-layout https://github.com/atlassia

ZhengFang 762 Nov 29, 2022