React bindings for SortableJS

Overview

react-sortablejs

React bindings to SortableJS

semantic-release

Please note that this is not considered ready for production, as there are still a number of bugs being sent through.

Features

Installation

sortablejs and @types/sortbalejs are peer dependencies. The latter only used if intellisense/typescript is desired.

npm install --save react-sortablejs sortablejs
npm install --save-dev @types/sortablejs

# OR
yarn add react-sortablejs sortablejs
yarn add -D @types/sortablejs

Learn

Here is the TLDR of what sortable is:

- Shopping List: # list of items / sortable. This represents `react-sortablejs`
  - eggs # list item. These are all the items in the list and is what you move around.
  - bread # list item
  - milk # list item

Usage/Examples

Function Component

import React, { FC, useState } from "react";
import { ReactSortable } from "react-sortablejs";

interface ItemType {
  id: number;
  name: string;
}

export const BasicFunction: FC = (props) => {
  const [state, setState] = useState<ItemType[]>([
    { id: 1, name: "shrek" },
    { id: 2, name: "fiona" },
  ]);

  return (
    <ReactSortable list={state} setList={setState}>
      {state.map((item) => (
        <div key={item.id}>{item.name}</div>
      ))}
    </ReactSortable>
  );
};

Class Component

import React, { Component } from "react";
import { ReactSortable } from "react-sortablejs";

interface BasicClassState {
  list: { id: string; name: string }[];
}

export class BasicClass extends Component<{}, BasicClassState> {
  state: BasicClassState = {
    list: [{ id: "1", name: "shrek" }],
  };
  render() {
    return (
      <ReactSortable
        list={this.state.list}
        setList={(newState) => this.setState({ list: newState })}
      >
        {this.state.list.map((item) => (
          <div key={item.id}>{item.name}</div>
        ))}
      </ReactSortable>
    );
  }
}

Plugins

Sortable has some pretty cool plugins such as MultiDrag and Swap.

By Default:

  • AutoScroll is premounted and enabled.
  • OnSpill is premounted and NOT enabled.
  • MultiDrag and Swap and NOT premounted and NOT enabled

You must mount mount the plugin with sortable ONCE ONLY.

import React from "react";
import { ReactSortable, Sortable, MultiDrag, Swap } from "react-sortablejs";

// mount whatever plugins you'd like to. These are the only current options.
Sortable.mount(new MultiDrag(), new Swap());

const App = () => {
  const [state, setState] = useState([
    { id: 1, name: "shrek" },
    { id: 2, name: "fiona" },
  ]);

  return (
    <ReactSortable
      multiDrag // enables mutidrag
      // OR
      swap // enables swap
    >
      {state.map((item) => (
        <div key={item.id}>{item.name}</div>
      ))}
    </ReactSortable>
  );
};

Sortable API

For a comprehensive list of options, please visit https://github.com/SortableJS/Sortable#options.

Those options are applied as follows.

Sortable.create(element, {
  group: " groupName",
  animation: 200,
  delayOnTouchStart: true,
  delay: 2,
});

// --------------------------
// Will now be..
// --------------------------

import React from "react";
import { ReactSortable } from "react-sortablejs";

const App = () => {
  const [state, setState] = useState([
    { id: 1, name: "shrek" },
    { id: 2, name: "fiona" },
  ]);

  return (
    <ReactSortable
      // here they are!
      group="groupName"
      animation={200}
      delayOnTouchStart={true}
      delay={2}
    >
      {state.map((item) => (
        <div key={item.id}>{item.name}</div>
      ))}
    </ReactSortable>
  );
};

React API

id, className, style

Thes are all defaults DOM attributes. Nothing special here.

list

The same as state in const [ state, setState] = useState([{ id: 1}, {id: 2}])

state must be an array of items, with each item being an object that has the following shape:

  /** The unique id associated with your item. It's recommended this is the same as the key prop for your list item. */
  id: string | number;
  /** When true, the item is selected using MultiDrag */
  selected?: boolean;
  /** When true, the item is deemed "chosen", which basically just a mousedown event. */
  chosen?: boolean;
  /** When true, it will not be possible to pick this item up in the list. */
  filtered?: boolean;
  [property: string]: any;

setList

The same as setState in const [ state, setState] = useState([{ id: 1}, {id: 2}])

clone

If you're using {group: { name: 'groupName', pull: 'clone'}}, this means your in 'clone' mode. You should provide a function for this.

Check out the source code of the clone example for more information. I'll write it here soon.

tag

ReactSortable is a div element by default. This can be changed to be any HTML element (for example ul, ol) or can be a React component.

This value, be the component or the HTML element should be passed down under props.tag.

Let's explore both here.

HTML Element

Here we will use a ul. You can use any HTML. Just add the string and ReactSortable will use a li instead of a div.

import React, { FC, useState } from "react";
import { ReactSortable } from "react-sortablejs";

export const BasicFunction: FC = (props) => {
  const [state, setState] = useState([{ id: "1", name: "shrek" }]);

  return (
    <ReactSortable tag="ul" list={state} setList={setState}>
      {state.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ReactSortable>
  );
};

Custom Component

When using a custom component in the tag prop, the only component it allows is a forwardRef component. Currently we only support components who use the React.forwardRef API.

If it doesn't have one, you can add one using React.forwardRef().

todo: Some third party UI components may have nested elements to create the look they're after. This could be an issue and not sure how to fix.

import React, { FC, useState, forwardRef } from "react";
import { ReactSortable } from "react-sortablejs";

// This is just like a normal component, but now has a ref.
const CustomComponent = forwardRef<HTMLDivElement, any>((props, ref) => {
  return <div ref={ref}>{props.children}</div>;
});

export const BasicFunction: FC = (props) => {
  const [state, setState] = useState([
    { id: 1, name: "shrek" },
    { id: 2, name: "fiona" },
  ]);

  return (
    <ReactSortable tag={CustomComponent} list={state} setList={setState}>
      {state.map((item) => (
        <div key={item.id}>{item.name}</div>
      ))}
    </ReactSortable>
  );
};

How does it work?

Sortable affects the DOM, adding, and removing nodes/css when it needs to in order to achieve the smooth transitions we all know an love. This component reverses many of it's actions of the DOM so React can handle this when the state changes.

Caveats / Gotchas

key !== index

DO NOT use the index as a key for your list items. Sorting will not work.

In all the examples above, I used an object with an ID. You should do the same!

I may even enforce this into the design to eliminate errors.

Nesting

Problem

Basically the child updates the state twice. I'm working on this.

What does work?

Our usage indicates that as long as we only move items between lists that don't use the same setState function.

I hope to provide an example soon.

Solutions

We don't have anything that works 100%, but here I'd like to spit ball some potential avenues to look down.

  • Use onMove to handle state changes instead of onAdd,onRemove, etc.
  • Create a Sortable plugin specifically for react-sortbalejs
Comments
  • Uncaught Sortable: `el` must be HTMLElement, and not [object Object]

    Uncaught Sortable: `el` must be HTMLElement, and not [object Object]

    Example source code gives following exception:

    Uncaught Sortable: `el` must be HTMLElement, and not [object Object]
    

    Nothing gets rendered.

    Libraries versions used:

    • Sortable 1.4.2
    • react-sortablejs v1.0.0
    • React.version "15.0.2"
    • ReactDOM.version "15.0.2"
    opened by garmoshka-mo 19
  • [bug] Attempted import error: 'MultiDrag' is not exported from 'sortablejs'

    [bug] Attempted import error: 'MultiDrag' is not exported from 'sortablejs'

    Describe the bug Getting this error in a Next.js application since v5 was released:

    error - ./node_modules/react-sortablejs/dist/index.es.js
    Attempted import error: 'MultiDrag' is not exported from 'sortablejs'.
    

    Information This is required. Issues without this critical information will be closed.

    Versions: react-sortable = ^5.0.4 react = 16.13.1

    The only thing that works for me is freezing react-sortable version to 2.0.11 exactly.

    type:bug released 
    opened by icflorescu 17
  • Change disabled option at runtime

    Change disabled option at runtime

    Hey, would it be please possible to change disabled option at runtime? I have noticed that only the first value is (true or false) is used for the whole lifetime of . That's quite uncomfortable for instance when you want to send requests to api between changes. Tested at version 2.0.2

    type:enhancement 
    opened by Bast1onCZ 14
  • Failed to execute 'insertBefore' on 'Node'

    Failed to execute 'insertBefore' on 'Node'

    Hi! some time. when move block from one column to top another, browser catch error in console Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.. After this error app broken and need reload page.

    Code broken on this line https://github.com/cheton/react-sortable/blob/master/src/index.jsx#L63

    opened by anagami 14
  • Passing Model via .props rather than .state / Syncing with Redux or other Flux implementation

    Passing Model via .props rather than .state / Syncing with Redux or other Flux implementation

    Hello & thanks for a great component! Working on integrating it with my project now.

    One thing I'm curious about is a scenario where I'm passing my would-be model to my component via props (via Redux), but the HoC is expecting my model to be available via state.

    For now, I'm going to add some glue to keep my component's state up-to-date with the props being passed in. But it seems like an anti-pattern.

    Wondering if you had any thoughts or experience wiring this up to a Flux implementation?

    My gut feeling is that it would be nice to specify whether the model is on state or props... Maybe something like options.modelContainer: 'props' // default: 'state'

    Seems like I should be able to update Redux using an action dispatcher call using one of the provided callback options.

    Anyway, thanks again.

    Update: just noticed the store option... might be able to use this...

    Update 2: I ended up switching to https://github.com/gaearon/react-dnd, which definitely has a little bit of a learning curve to it compared to the simplicity of react-sortable. But ultimately, I found it more flexible for what I was trying to achieve.

    type:enhancement 
    opened by jakedowns 14
  • Typescript Support

    Typescript Support

    Hi All,

    I know there is an @types/sortablejs file out in the wild, but in the react world I don't know how to hook it up correctly, due to unfimilarity with the react specific implementation of SortableJs. I've used VueJs Component which works easily and am familiar with many SortableJS options.

    From the example in this README.md, I entered this code:

    import uniqueId from 'lodash/uniqueId';
    import React from 'react';
    import Sortable from 'react-sortablejs';
    

    The squiggly lines of death are under 'react-sortablejs', which displays the following message on hover:

    Try `npm install @types/react-sortablejs` if it exists or
    add a new declaration (.d.ts) file containing `declare module 'react-sortablejs';
    

    I am trying to go through the typescript documentation for an answer, but can't figure out how to extend the sortablejs types into react-sortablejs

    Any ideas?

    On resolution of this, we should link @types/sortablejs as a dependency in future builds alongside a declaration form for this package. I'll be happy to try doing this once I start using this Component.

    type:enhancement 
    opened by waynevanson 12
  • Attempted import error

    Attempted import error

    Failed to compile.

    Got this error. Any thoughts?

    ./node_modules/react-sortablejs-typescript/dist/index.es.js
    Attempted import error: 'AutoScroll' is not exported from 'sortablejs'
    
    opened by exsesx 11
  • Doesn't work in new chrome browser

    Doesn't work in new chrome browser

    Works fine in old chrome browser, in new version doesn't work. Nothing heppening. Tested it in lots of Laptops and so. Looks like onChange doesn't work

    opened by kostiantyn-solianyk 11
  • Is there an easy way to access attributes of target element?

    Is there an easy way to access attributes of target element?

    I have a custom data attribute on my draggable elements that consist of some extra information. I can access the attributes of the dragged item but I cannot find a way to get attributes of the target element.

    onChange={(order, sortable, evt) => {
        console.log(evt.item.attributes.data.value) // works fine
        console.log(evt.target.attributes.data.value) // need something like this
    }
    

    How can do this?

    feedback:question status:needs-investigation 
    opened by thewebsitedev 11
  • Fix work with frozen item objects

    Fix work with frozen item objects

    The fix for the issue: https://github.com/SortableJS/react-sortablejs/issues/159.

    I don't set the object frozen by myself, probably it's some other library, that I can't track. I hope, you'll accept the fix, it's very essential for me.

    I tried to follow your code style as much as possible. Also, I removed redundant spread because map already creates a new array. I've checked other places, it seems they won't have problems with frozen objects.

    opened by DZakh 10
  • Not update sortable items

    Not update sortable items

    Hi! i have peace of code

    class Todos extends Component {
        state = {
            todos: []
        }
    
        componentWillMount() {
            this.setState({
                todos: this.props.todos
            })
        }
        componentWillReceiveProps(nextProps) {
            this.setState({
                todos: nextProps.todos
            })
        }
    
        renderTodos() {
            return this.state.todos.map(todo => {
                return <Todo {...todo} key={todo.id} />
            })
        }
        render() {
            let opt = {
                onUpdate: this.onUpdate,
                model: 'todos'
            }
    
            return <div>
                <Sortable tag="div" className="todos-wrapper" options={opt}>
                    {this.renderTodos()}
                </Sortable>
            </div>
        }
    }
    

    list of todos come from reducer. onUpdate - function that send new position to server, server response with new list of todos. New list todos set as props to component Todos. If server response with previous version of sorting, sortable items dont change to new positions

    opened by anagami 9
  • ReactSortable element list type issues

    ReactSortable element list type issues

    Hello team. Thanks for creating a greate libary for me for easy to sortable a list, i'm using ReactSortable for sorting my person list with typescript, when i create a state with type IPerson[], then i put the state into the ReactSortable Element, the list prop show this message: Type 'IPerson[]' is not assignable to type 'ItemInterface[]'. How can i solve this, is this a bug or i am doing wrong some where, thanks for reading my issue, hope you guy can support me as soon as possible.

    image

    opened by sergiotran 0
  • [bug] Sort property does not work properly

    [bug] Sort property does not work properly

    Describe the bug Changing sort property does not update functionality (sort is applied only onMount)

    To Reproduce <ReactSortable list={sort} setList={setList} sort={isSorting} >

    Steps to reproduce the behavior:

    1. Create a button that can change state isSorting, and render this ReactSortable next to it
    2. By clicking on the button you are not changing functionality

    Expected behavior that it will work

    Information After looking into your code you are creating Sortable object after onmount => but not updating i think you should be able to update Sortable object by option(name:String[, value:*]) method

    Versions - Look in your package.json for this information: react-sortable = 6.1.4 react = 18

    opened by Veragin 2
  • Is React-SortableJS 6.1.4 compatible with React 18?

    Is React-SortableJS 6.1.4 compatible with React 18?

    I have tried implementing this package (6.1.4) with React 18, and it looks like the state is not updated property after drop, if the approach is nested. Can someone please have a look on this?

    opened by SVenkat99 3
  • [bug]

    [bug]

    Describe the bug 安装6.1.4报错、低版本有ts警告

    To Reproduce Steps to reproduce the behavior: image

    Expected behavior A clear and concise description of what you expected to happen.

    Information This is required. Issues without this critical information will be closed.

    Versions - Look in your package.json for this information: react-sortable = ^6.1.4 react = 17.x

    Additional context Add any other context about the problem here.

    Please provide examples, screenshots or a code sandbox for faster resolution times.

    opened by Js-Man-H5 3
  • Error after building react app

    Error after building react app

    Describe the bug Safari Error: Unexpected token '='. Expected an opening '(' before a method's parameter list. I upgraded from 6.1.1 to 6.1.4 and got this issue in older version of safari. Specifically running v13.3.1 of ios

    Versions - Look in your package.json for this information: react-sortable = ^16.1.4 react = ^16.2.0

    opened by allaniftrue 0
Releases(v6.1.4)
Owner
SortableJS
A JavaScript library for reorderable drag-and-drop lists in modern browsers and touch devices
SortableJS
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
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
React Drag and Drop file input

React Drag and Drop file input

Tran Anh Tuat 45 Dec 30, 2022
An add-on backend for `react-dnd` that provides support for keyboards and screenreaders by default.

An add-on backend for `react-dnd` that provides support for keyboards and screenreaders by default.

Discord 569 Dec 31, 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
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

Streak 282 Dec 16, 2022
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

浅搁 224 Oct 9, 2022