node package manager

react-sortablejs

react-sortable build status Coverage Status

NPM

A React component built on top of Sortable (https://github.com/RubaXa/Sortable).

The sample code can be found in the examples directory.

Notice

There is a major breaking change since v1.0. Checkout Migration Guide while upgrading from earlier versions.

Installation

Webpack or Browserify

The easiest way to use react-sortablejs is to install it from npm and include it in your React build process using webpack or browserify.

npm install --save react react-dom sortablejs@1.5.0-rc1  # Install peerDependencies
npm install --save react-sortablejs

Checkout the examples directory for a complete setup.

Standalone ES5 module

You can create a standalone ES5 module as shown below:

$ git clone https://github.com/cheton/react-sortable.git
$ cd react-sortable
$ npm install
$ npm run build && npm run dist

Then, include these scripts into your html file:

<body>
  <div id="container"></div>
  <script src="http://fb.me/react-0.14.7.js"></script> 
  <script src="http://fb.me/react-dom-0.14.7.js"></script> 
  <script src="http://cdnjs.cloudflare.com/ajax/libs/Sortable/1.4.2/Sortable.min.js"></script> 
  <script src="dist/react-sortable.min.js"></script> 
</body>

Use <ReactSortable /> instead of <Sortable /> in your JSX code since the Sortable library will export a window.Sortable object if you're running JSX code directly in the browser. For example:

<ReactSortable
    tag="ul"
    onChange={(order) =>
        this.props.onChange(order);
    }}
>
    {items}
</ReactSortable>

Usage

File: sortable-list.jsx

import React from 'react';
import Sortable from 'react-sortablejs';
 
// Functional Component 
const SortableList = ({ items, onChange }) => {
    let sortable = null; // sortable instance 
    const reverseOrder = (evt) => {
        const order = sortable.toArray();
        onChange(order.reverse());
    };
    const listItems = items.map((val, key) => (<li key={key} data-id={val}>List Item: {val}</li>));
 
    return (
        <div>
            <button type="button" onClick={reverseOrder}>Reverse Order</button>
            <Sortable
                // Sortable options (https://github.com/RubaXa/Sortable#options) 
                options={{
                }}
 
                // [Optional] Use ref to get the sortable instance 
                // https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute 
                ref={(c) => {
                    if (c) {
                        sortable = c.sortable;
                    }
                }}
 
                // [Optional] A tag to specify the wrapping element. Defaults to "div". 
                tag="ul"
 
                // [Optional] The onChange method allows you to implement a controlled component and keep 
                // DOM nodes untouched. You have to change state to re-render the component. 
                // @param {Array} order An ordered array of items defined by the `data-id` attribute. 
                // @param {Object} sortable The sortable instance. 
                // @param {Event} evt The event object. 
                onChange={(order, sortable, evt) => {
                    onChange(order);
                }}
            >
                {listItems}
            </Sortable>
        </div>
    );
};
 
SortableList.propTypes = {
    items: React.PropTypes.array,
    onChange: React.PropTypes.func
};
 
export default SortableList;

File: index.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import SortableList from './sortable-list';
 
class App extends React.Component {
    state = {
        items: [1, 2, 3, 4, 5, 6]
    };
 
    render() {
        return (
            <SortableList
                items={this.state.items}
                onChange={(items) => {
                    this.setState({ items });
                }}
            >
            </SortableList>
        )
    }
};
 
ReactDOM.render(
    <App />,
    document.getElementById('container')
);

Examples

Uncontrolled Component

An uncontrolled component allows Sortable to touch DOM nodes. It's useful when you don't need to maintain any state changes.

import React from 'react';
import ReactDOM from 'react-dom';
import Sortable from 'react-sortablejs';
 
class App extends React.Component {
    state = {
        items: ['Apple', 'Banana', 'Cherry', 'Guava', 'Peach', 'Strawberry']
    };
 
    render() {
        const items = this.state.items.map((val, key) => (<li key={key} data-id={val}>{val}</li>));
 
        return (
            <div>
                <Sortable
                    tag="ul" // Defaults to "div" 
                >
                    {items}
                </Sortable>
            </div>
        );
    }
}
 
ReactDOM.render(
    <App />,
    document.getElementById('container')
);

Controlled Component

A controlled component will keep DOM nodes untouched. You have to change state to re-render the component.

import React from 'react';
import ReactDOM from 'react-dom';
import Sortable from '../src';
 
class App extends React.Component {
    state = {
        items: ['Apple', 'Banana', 'Cherry', 'Guava', 'Peach', 'Strawberry']
    };
 
    render() {
        const items = this.state.items.map((val, key) => (<li key={key} data-id={val}>{val}</li>));
 
        return (
            <div>
                <Sortable
                    tag="ul" // Defaults to "div" 
                    onChange={(order, sortable, evt) => {
                        this.setState({ items: order });
                    }}
                >
                    {items}
                </Sortable>
            </div>
        );
    }
}
 
ReactDOM.render(
    <App />,
    document.getElementById('container')
);

Shared Group

An example of using the group option to drag elements from one list into another.

File: shared-group.jsx

import React from 'react';
import Sortable from '../src';
 
// Functional Component 
const SharedGroup = ({ items }) => {
    items = items.map((val, key) => (<li key={key} data-id={val}>{val}</li>));
 
    return (
        <Sortable
            // See all Sortable options at https://github.com/RubaXa/Sortable#options 
            options={{
                group: 'shared'
            }}
            tag="ul"
        >
            {items}
        </Sortable>
    );
};
 
export default SharedGroup;

File: index.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import SharedGroup from './shared-group';
 
const App = (props) => {
    return (
        <div>
            <SharedGroup
                items={['Apple', 'Banaba', 'Cherry', 'Grape']}
            />
            <br/>
            <SharedGroup
                items={['Lemon', 'Orange', 'Pear', 'Peach']}
            />
        </div>
    );
};
 
ReactDOM.render(<App />, document.getElementById('container'));