Column moving
Change the order of columns, either manually (dragging them to another location), or programmatically (using Handsontable’s API methods).
Enable the plugin
To enable column moving, set the manualColumnMove configuration option to true.
A draggable move handle appears above the selected column header. You can click and drag it to any location in the grid.
<script setup lang="ts">import { ref } from 'vue';import { HotTable } from '@handsontable/vue3';import { registerAllModules } from 'handsontable/registry';import type { GridSettings } from 'handsontable/settings';
// register Handsontable's modulesregisterAllModules();
// generate an array of arrays with dummy dataconst data = new Array(200) // number of rows .fill(null) .map((_, row) => new Array(20) // number of columns .fill(null) .map((_, column) => `${row}, ${column}`) );
const hotSettings = ref<GridSettings>({ data, width: '100%', height: 320, rowHeaders: true, colHeaders: true, colWidths: 100, manualColumnMove: true, autoWrapRow: true, autoWrapCol: true, licenseKey: 'non-commercial-and-evaluation',});</script>
<template> <div id="example1"> <HotTable :settings="hotSettings" /> </div></template>Move column headers
When you move columns, the default column headers (A, B, C) stay in place.
<script setup lang="ts">import { ref } from 'vue';import { HotTable } from '@handsontable/vue3';import { registerAllModules } from 'handsontable/registry';import type { GridSettings } from 'handsontable/settings';
// register Handsontable's modulesregisterAllModules();
const hotSettings = ref<GridSettings>({ data: [ ['A1', 'B1', 'C1'], ['A2', 'B2', 'C2'], ['A3', 'B3', 'C3'], ], colHeaders: true, rowHeaders: true, manualColumnMove: true, autoWrapRow: true, autoWrapCol: true, height: 'auto', licenseKey: 'non-commercial-and-evaluation',});</script>
<template> <div id="example2"> <HotTable :settings="hotSettings" /> </div></template>But, if you configure the colHeaders option with your own column labels (e.g., One, Two, Three), your headers move along with the columns.
<script setup lang="ts">import { ref } from 'vue';import { HotTable } from '@handsontable/vue3';import { registerAllModules } from 'handsontable/registry';import type { GridSettings } from 'handsontable/settings';
// register Handsontable's modulesregisterAllModules();
const hotSettings = ref<GridSettings>({ data: [ ['A1', 'B1', 'C1'], ['A2', 'B2', 'C2'], ['A3', 'B3', 'C3'], ], colHeaders: ['One', 'Two', 'Three'], rowHeaders: true, manualColumnMove: true, autoWrapRow: true, autoWrapCol: true, height: 'auto', licenseKey: 'non-commercial-and-evaluation',});</script>
<template> <div id="example3"> <HotTable :settings="hotSettings" /> </div></template>Set a pre-defined column order
Instead of setting manualColumnMove to true, you can pass an array of physical column indexes to define the initial visual order of columns on render.
Each position in the array corresponds to a visual (display) position, and the value at that position is the physical (source data) column index. For example:
manualColumnMove: [1, 0, 2]This renders the columns in the following order:
- Visual position 0 → physical column
1 - Visual position 1 → physical column
0 - Visual position 2 → physical column
2
The array must contain all physical column indexes (its length must equal the total number of columns). After the initial render, users can still drag columns to change the order further.
For more on how physical and visual indexes relate, see Understanding data and indexes.
Control column moving
Use the beforeColumnMove hook to decide whether each column move is allowed. Returning false cancels the move while keeping the manualColumnMove plugin enabled.
In the following example, select Allow column moving before you drag a column to a new position. Clear the checkbox to block column moving again.
<script setup lang="ts">import { ref } from 'vue';import { HotTable } from '@handsontable/vue3';import { registerAllModules } from 'handsontable/registry';import type { GridSettings } from 'handsontable/settings';
registerAllModules();
const allowColumnMoving = ref(false);
const hotSettings: GridSettings = { data: [ ['SKU-4821', 'Wireless keyboard', 'Harbor Goods', 142], ['SKU-0093', 'USB-C dock', 'Vertex Supply', 67], ['SKU-3148', '27-inch monitor', 'Alpine Supply Co.', 24], ['SKU-7720', 'Laptop stand', 'Northstar Wholesale', 89], ['SKU-1056', 'Noise-canceling headset', 'Summit Distribution', 35], ], colHeaders: ['SKU', 'Product', 'Supplier', 'Stock'], rowHeaders: true, manualColumnMove: true, beforeColumnMove: () => allowColumnMoving.value, stretchH: 'all', height: 'auto', licenseKey: 'non-commercial-and-evaluation',};</script>
<template> <div id="example4"> <div class="example-controls-container"> <div class="controls"> <label> <input v-model="allowColumnMoving" type="checkbox" /> Allow column moving </label> </div> </div> <HotTable :settings="hotSettings" /> </div></template>Result
After completing this guide, you can reorder columns by dragging them with the mouse or by calling dragColumns() and moveColumns() programmatically. You can also set a pre-defined column order at initialization or use beforeColumnMove to block individual moves.
Drag and move actions of the ManualColumnMove plugin
There are significant differences between the plugin’s dragColumns and moveColumns API functions. Both of them change the order of columns, but they rely on different kinds of indexes. The differences between them are shown in the diagrams below.
Both of these methods trigger the beforeColumnMove and afterColumnMove hooks, but only dragColumns passes the dropIndex argument to them.
The dragColumns method has a dropIndex parameter, which points to where the elements are being dropped.
The moveColumns 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.
The moveColumns 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 beforeColumnMove and afterColumnMove hooks help in determine such situations.
Related API reference
Configuration options
Core methods
Hooks
Plugins