Row drag and drop in React TreeGrid

11 Oct 202518 minutes to read

TreeGrid rows can be reordered or dropped into another TreeGrid or custom control by setting allowRowDragAndDrop to true.

To use row drag and drop, inject the RowDD module into the TreeGrid.

Drag and drop within TreeGrid

Row drag and drop supports reordering within the same TreeGrid using the drag icon. Enable it by setting allowRowDragAndDrop to true. Rows can be dropped above, below, or as a child of the target row based on the drop position.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TreeGridComponent, ColumnsDirective, ColumnDirective, Inject, RowDD } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';
class App extends React.Component {
    selectionSettings = { type: 'Multiple' };
    render() {
        return <TreeGridComponent dataSource={sampleData} allowRowDragAndDrop={true} treeColumnIndex={1} childMapping='subtasks' height='270' selectionSettings={this.selectionSettings}>
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
              <ColumnDirective field='progress' headerText='Progress' width='80' textAlign='Right'/>
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>;
    }
}
ReactDOM.render(<App />, document.getElementById('treegrid'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TreeGridComponent, ColumnsDirective, ColumnDirective, Inject, RowDD, RowDropSettingsModel, SelectionSettingsModel } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';

class App extends React.Component<{}, {}>{

    public selectionSettings: SelectionSettingsModel = { type: 'Multiple' };

    render() {
        return <TreeGridComponent dataSource={sampleData} allowRowDragAndDrop={true} treeColumnIndex={1} childMapping='subtasks' height='270' selectionSettings={this.selectionSettings} >
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
              <ColumnDirective field='progress' headerText='Progress' width='80' textAlign='Right' />
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>
    }
}
ReactDOM.render(<App />, document.getElementById('treegrid'));

  • Selection must be enabled for row drag and drop.
  • Multiple rows can be selected by clicking and dragging inside the TreeGrid.
  • For multiple row selection, set the type property to multiple.
  • The isPrimaryKey property is required to perform row drag-and-drop.

Drag and drop to another TreeGrid

To drag and drop between two TreeGrids, enable allowRowDragAndDrop and set the target TreeGrid ID in the targetID property of rowDropSettings.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TreeGridComponent, RowDD, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';
class Source extends React.Component {
    data = sampleData;
    rowDropSettings = { targetID: 'DestGrid' };
    selectionSettings = { type: 'Multiple' };
    style = { marginBottom: '20px' };
    render() {
        return <TreeGridComponent id='TreeGrid' dataSource={sampleData} treeColumnIndex={1} allowRowDragAndDrop={true} rowDropSettings={this.rowDropSettings} selectionSettings={this.selectionSettings} childMapping='subtasks' height='275'>
                <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date'/>
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
          </TreeGridComponent >;
    }
}
class Target extends React.Component {
    data = [];
    rowDropSettings = { targetID: 'TreeGrid' };
    selectionSettings = { type: 'Multiple' };
    render() {
        return <TreeGridComponent treeColumnIndex={1} id='DestGrid' allowRowDragAndDrop={true} rowDropSettings={this.rowDropSettings} selectionSettings={this.selectionSettings} childMapping='subtasks' height='275'>
        <ColumnsDirective>
        <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
        <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
        <ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date'/>
        <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
      </ColumnsDirective>
      <Inject services={[RowDD]}/>
</TreeGridComponent>;
    }
}
   
function App() {
    return <div>
            <Source></Source>
            <Target></Target>
           </div>;
}
ReactDOM.render(<App />, document.getElementById('treegrid'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TreeGridComponent, RowDD, ColumnsDirective, ColumnDirective, RowDropSettingsModel, SelectionSettingsModel, Inject } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';

class Source extends React.Component<{}, {}>{
    public data: Object[] = sampleData;
    public rowDropSettings: RowDropSettingsModel = { targetID: 'DestGrid' };
    public selectionSettings: SelectionSettingsModel = { type: 'Multiple' };
    public style = { marginBottom: '20px' };
    render() {
        return <TreeGridComponent id='TreeGrid' dataSource={sampleData} treeColumnIndex={1} allowRowDragAndDrop={true}
        rowDropSettings={this.rowDropSettings} selectionSettings={this.selectionSettings}
         childMapping='subtasks' height='275'>
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date' />
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>
    }
}

class Target extends React.Component<{}, {}>{
    public data: Object[] = [];
    public rowDropSettings: RowDropSettingsModel = { targetID: 'TreeGrid' };
    public selectionSettings: SelectionSettingsModel = { type: 'Multiple' };
    render() {
        return <TreeGridComponent treeColumnIndex={1} id='DestGrid' allowRowDragAndDrop={true}
        rowDropSettings={this.rowDropSettings} selectionSettings={this.selectionSettings}
         childMapping='subtasks' height='275'>
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date' />
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>
    }
}


function App(){
    return <div>
            <Source></Source>
            <Target></Target>
           </div>
}

ReactDOM.render(<App />, document.getElementById('treegrid'));

Drag and drop events

The following events are triggered during row drag and drop:

  • rowDragStartHelper - Triggers when the drag icon or row is clicked; customize the drag element based on criteria.
  • rowDragStart - Triggers when a row drag starts.
  • rowDrag - Triggers while a row is being dragged.
  • rowDrop - Triggers when the dragged element is dropped on the target element.

Prevent reordering a row as child to another row

Prevent dropping rows as children by setting cancel to true in the rowDrop event arguments. After canceling, adjust the drop position programmatically using the reorderRows method.

In the following example, the drop action is canceled and the row is dropped above the target row.

import * as React from 'react';
import { TreeGridComponent, ColumnsDirective, ColumnDirective, Inject, RowDD } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';
class App extends React.Component {
    rowDrop(args) {
        if (args.dropPosition == 'middleSegment') {
            args.cancel = true;
            this.treegridInstance.reorderRows([args.fromIndex], args.dropIndex, 'above');
        }
        render();
        {
            return <TreeGridComponent ref={(treegrid) => (this.treegridInstance = treegrid)} allowRowDragAndDrop={true} dataSource={sampleData} treeColumnIndex={1} childMapping='subtasks' height='270' rowDrop={this.rowDrop.bind(this)}>
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
              <ColumnDirective field='progress' headerText='Progress' width='80' textAlign='Right'/>
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>;
        }
    }
}
ReactDOM.render(<App />, document.getElementById('treegrid'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { TreeGridComponent, ColumnsDirective, ColumnDirective, Inject, RowDD, RowDropSettingsModel, SelectionSettingsModel } from '@syncfusion/ej2-react-treegrid';
import { sampleData } from './datasource';

class App extends React.Component<{}, {}>{
       public treegridInstance: TreeGridComponent;
       public rowDrop(args: any) {
          if (args.dropPosition == 'middleSegment') {
               args.cancel = true;
               this.treegridInstance.reorderRows([args.fromIndex], args.dropIndex, 'above');
          }
       }
       render() {
        return <TreeGridComponent ref={(treegrid) => (this.treegridInstance = treegrid)} allowRowDragAndDrop={true} dataSource={sampleData} treeColumnIndex={1} childMapping='subtasks' height='270' rowDrop={this.rowDrop.bind(this)} >
            <ColumnsDirective>
              <ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'></ColumnDirective>
              <ColumnDirective field='taskName' headerText='Task Name' width='180'></ColumnDirective>
              <ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
              <ColumnDirective field='progress' headerText='Progress' width='80' textAlign='Right' />
            </ColumnsDirective>
            <Inject services={[RowDD]}/>
        </TreeGridComponent>
    }
}
ReactDOM.render(<App />, document.getElementById('treegrid'));