Skip to content

Change the order of rows, either manually (dragging them to another location), or programmatically (using Handsontable’s API methods).

Enable the ManualRowMove plugin

To enable row moving, set the manualRowMove option to true.

A draggable move handle appears above the selected row header. You can click and drag it to any location in the row header body.

JavaScript
import { HotTable } from '@handsontable/react-wrapper';
import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modules
registerAllModules();
// generate an array of arrays with dummy data
const data = new Array(200) // number of rows
.fill(0)
.map((_, row) =>
new Array(20) // number of columns
.fill(0)
.map((_, column) => `${row}, ${column}`)
);
const ExampleComponent = () => {
return (
<HotTable
data={data}
width="100%"
height={320}
rowHeaders={true}
colHeaders={true}
colWidths={100}
manualRowMove={true}
autoWrapRow={true}
autoWrapCol={true}
licenseKey="non-commercial-and-evaluation"
/>
);
};
export default ExampleComponent;
TypeScript
import { HotTable } from '@handsontable/react-wrapper';
import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modules
registerAllModules();
// generate an array of arrays with dummy data
const data = new Array(200) // number of rows
.fill(0)
.map((_, row) =>
new Array(20) // number of columns
.fill(0)
.map((_, column) => `${row}, ${column}`)
);
const ExampleComponent = () => {
return (
<HotTable
data={data}
width="100%"
height={320}
rowHeaders={true}
colHeaders={true}
colWidths={100}
manualRowMove={true}
autoWrapRow={true}
autoWrapCol={true}
licenseKey="non-commercial-and-evaluation"
/>
);
};
export default ExampleComponent;

Set a pre-defined row order

Instead of setting manualRowMove to true, you can pass an array of physical row indexes to define the initial visual order of rows on render.

Each position in the array corresponds to a visual (display) position, and the value at that position is the physical (source data) row index. For example:

manualRowMove: [2, 0, 1]

This renders the rows in the following order:

  • Visual position 0 → physical row 2
  • Visual position 1 → physical row 0
  • Visual position 2 → physical row 1

The array must contain all physical row indexes (its length must equal the total number of rows). After the initial render, users can still drag rows to change the order further.

Drag and move actions of manualRowMove plugin

There are significant differences between the plugin’s dragRows and moveRows API functions. Both of them change the order of rows, but they rely on different kinds of indexes. The differences between them are shown in the diagrams below.

Both of these methods trigger the beforeRowMove and afterRowMove hooks, but only dragRows passes the dropIndex argument to them.

The dragRows method has a dropIndex parameter, which points to where the elements are being dropped.

dragRows method

The moveRows method has a finalIndex parameter, which points to where the elements will be placed after the moving action - finalIndex being the index of the first moved element.

moveRows method

The moveRows function cannot perform some actions, e.g., more than one element can’t be moved to the last position. In this scenario, the move will be cancelled. The Plugin’s isMovePossible API method and the movePossible parameters beforeRowMove and afterRowMove hooks help in determine such situations.

Configuration options

Core methods

Hooks

Plugins