Configuration options
Configure your grid down to each column, row, and cell, using various built-in options that control Handsontable’s behavior and user interface.
Overview
To apply configuration options, pass them as a second argument of the Handsontable constructor, using the object literal notation:
import Handsontable from "handsontable";
const container = document.querySelector('#example');const hot = new Handsontable(container, { // configuration options, in the object literal notation licenseKey: "non-commercial-and-evaluation", data: [ ['A1', 'B1', 'C1', 'D1'], ['A2', 'B2', 'C2', 'D2'], ['A3', 'B3', 'C3', 'D3'], ], width: 400, height: 300, colHeaders: true, rowHeaders: true, customBorders: true, dropdownMenu: true, multiColumnSorting: true, filters: true, manualRowMove: true,});Depending on your needs, you can apply configuration options to different elements of your grid, such as:
- The entire grid
- Individual columns
- Individual rows
- Individual cells
- Individual grid elements, based on any logic you implement
For the full list of available configuration options, see the configuration options’ API reference.
Cascading configuration
Handsontable’s configuration cascades down:
- From the top-level grid options (
GlobalMeta) - Through the mid-level column options (
ColumnMeta) - To the bottom-level cell options (
CellMeta)
When you modify the mid-level column options (using the columns option):
- The options that you change overwrite the top-level grid options.
- The options that you change cascade down to the bottom-level cell options.
- Any unchanged options are inherited from the top-level grid options.
When you modify the bottom-level cell options (using the cell option):
- The options that you change overwrite the top-level grid options.
- The options that you change overwrite the mid-level column options.
- Any unchanged options are inherited from the mid-level column options or the top-level grid options.
When you modify any options with the cells function, the changes overwrite all other options.
For more details on Handsontable’s cascading configuration, see the MetaManager class.
Plugin options
Configuration options can come from:
If you use Handsontable through modules: to use an option that comes from a Handsontable plugin, you need to import and register that plugin when initializing your Handsontable instance.
To find out if an option comes from a plugin, check the Category label in the configuration options’ API reference.
Set grid options
To apply configuration options to the entire grid, pass your options as a second argument of the Handsontable constructor, using the object literal notation.
For example, to set the entire grid’s width and height:
const hot = new Handsontable(container, { // top-level grid options that apply to the entire grid width: 400, height: 300});Example
To configure each cell in the grid as read-only, apply the readOnly option as a top-level grid option.
The top-level grid options cascade down:
- To the mid-level column options
- To the bottom-level cell options
As a result, each cell in the grid is read-only:
import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector('#example1');const data = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, readOnly: true, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, autoWrapRow: true, autoWrapCol: true,});
// checks a cell's options// returns `true`hot.getCellMeta(0, 0).readOnly;import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector<HTMLDivElement>('#example1')!;
const data: Handsontable.CellValue[][] = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, readOnly: true, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, autoWrapRow: true, autoWrapCol: true,});
// checks a cell's options// returns `true`hot.getCellMeta(0, 0).readOnly;Set column options
To apply configuration options to an individual column (or a range of columns), use the columns option.
const hot = new Handsontable(container, { columns: [ {}, {}, // column options, apply to each cell of the third (by physical index) column { readOnly: true, }, ],});Example
In the example below, the columns option is set to a function.
The function applies the readOnly: true option to each column that has a physical index of either 2 or 8.
The modified mid-level column options:
- Overwrite the top-level grid options
- Cascade down to the bottom-level cell options
As a result, each cell in the third and ninth columns is read-only:
import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector('#example2');const data = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, readOnly: false, columns: (index) => { return { type: index > 0 ? 'numeric' : 'text', readOnly: index === 2 || index === 8, }; }, autoWrapRow: true, autoWrapCol: true,});
// checks a cell's options// returns `false`hot.getCellMeta(0, 0).readOnly;// returns `true`hot.getCellMeta(0, 2).readOnly;import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector<HTMLDivElement>('#example2')!;
const data: Handsontable.CellValue[][] = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, readOnly: false, columns: (index: number) => { return { type: index > 0 ? 'numeric' : 'text', readOnly: index === 2 || index === 8, }; }, autoWrapRow: true, autoWrapCol: true,});
// checks a cell's options// returns `false`hot.getCellMeta(0, 0).readOnly;
// returns `true`hot.getCellMeta(0, 2).readOnly;Set row options
To apply configuration options to an individual row (or a range of rows), use the cells option.
Any options modified through cells overwrite all other options.
The function can take three arguments:
row: a row coordinate (a physical index)col: a column coordinate (a physical index)prop: if yourdatais an array of objects,propis a property name for a column’s data source object.
If yourdatais an array of arrays,propis the same ascol.
const hot = new Handsontable(container, { // the `cells` options overwrite all other options cells(row, col, prop) { if (row === 1 || row === 4) { return { // row options, which apply to each cell of the second row // and to each cell of the fifth row readOnly: true, }; } }});Example
In the example below, the cells option sets each cell in the first and fourth row as readOnly.
Options modified through cells overwrite all other options.
import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector('#example3');const data = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, cells: (row, col) => { return row === 1 || row === 4 ? { readOnly: true } : {}; }, autoWrapRow: true, autoWrapCol: true,});
// checks a cell's options// returns `false`hot.getCellMeta(0, 0).readOnly;// returns `true`hot.getCellMeta(0, 1).readOnly;import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector<HTMLDivElement>('#example3')!;
const data: Handsontable.CellValue[][] = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, cells: (row: number, col: number) => { return row === 1 || row === 4 ? { readOnly: true } : {}; }, autoWrapRow: true, autoWrapCol: true,});
// checks a cell's options// returns `false`hot.getCellMeta(0, 0).readOnly;
// returns `true`hot.getCellMeta(0, 1).readOnly;Set cell options
To apply configuration options to individual cells, use the cell option.
const hot = new Handsontable(container, { cell: [ { // cell options, apply only to a cell with coordinates (0, 0) row: 0, col: 0, readOnly: true, }, { // cell options, apply only to a cell with coordinates (1, 1) row: 1, col: 1, readOnly: true, } ], autoWrapRow: true, autoWrapCol: true,});Example
In the example below, the cell option sets cell A1(0, 0) and cell B2(1, 1) as readOnly.
The modified cell options:
- Overwrite the top-level grid options
- Overwrite mid-level column options
import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector('#example4');const data = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, readOnly: false, cell: [ { // bottom-level cell options overwrite the top-level grid options // apply only to a cell with coordinates (0, 0) row: 0, col: 0, readOnly: true, }, { // bottom-level cell options overwrite the top-level grid options // apply only to a cell with coordinates (1, 1) row: 1, col: 1, readOnly: true, }, ], autoWrapRow: true, autoWrapCol: true,});
// checks a cell's options// returns `true`hot.getCellMeta(0, 0).readOnly;// returns `false`hot.getCellMeta(0, 1).readOnly;import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector<HTMLDivElement>('#example4')!;
const data: Handsontable.CellValue[][] = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, readOnly: false, cell: [ { // bottom-level cell options overwrite the top-level grid options // apply only to a cell with coordinates (0, 0) row: 0, col: 0, readOnly: true, }, { // bottom-level cell options overwrite the top-level grid options // apply only to a cell with coordinates (1, 1) row: 1, col: 1, readOnly: true, }, ], autoWrapRow: true, autoWrapCol: true,});
// checks a cell's options// returns `true`hot.getCellMeta(0, 0).readOnly;
// returns `false`hot.getCellMeta(0, 1).readOnly;Read cell options
When Handsontable is running, you can check a cell’s current options, using the getCellMeta() method.
The getCellMeta() method returns an object with:
For example:
import Handsontable from 'handsontable';
const container = document.querySelector('#example');const hot = new Handsontable(container, { // top-level grid options that apply to the entire grid data: [ ['A1', 'B1', 'C1', 'D1'], ['A2', 'B2', 'C2', 'D2'], ['A3', 'B3', 'C3', 'D3'], ], licenseKey: 'non-commercial-and-evaluation', width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, // in the top-level grid options, all cells are read-only readOnly: false, cell: [ { // bottom-level cell options overwrite the top-level grid options // apply only to a cell with coordinates (1, 1) row: 1, col: 1, readOnly: true, } ]});
// for cell (0, 0), the `readOnly` option is the default (`false`)// returns `false`hot.getCellMeta(0, 0).readOnly;
// for cell (1, 1), the `cell` option overwrote the default `readOnly` value// returns `true`hot.getCellMeta(1, 1).readOnly;Change cell options
When Handsontable is running, you can change the initial cell options, using the setCellMeta() method.
For example:
import Handsontable from 'handsontable';
const container = document.querySelector('#example');const hot = new Handsontable(container, { // top-level grid options that apply to the entire grid data: [ ['A1', 'B1', 'C1', 'D1'], ['A2', 'B2', 'C2', 'D2'], ['A3', 'B3', 'C3', 'D3'], ], licenseKey: 'non-commercial-and-evaluation', width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true,});
// changes the `readOnly` option of cell (1, 1) back to `false`hot.setCellMeta(1, 1, 'readOnly', false);
// returns `false`hot.getCellMeta(1, 1).readOnly;Implement custom logic
You can apply configuration options to individual grid elements (columns, rows, cells), based on any logic you implement, using the cells option.
The cells option overwrites all other options.
The function can take three arguments:
row: a row coordinate (a physical index)col: a column coordinate (a physical index)prop: if yourdatais an array of objects,propis a property name for a column’s data source object.
If yourdatais an array of arrays,propis the same ascol.
const hot = new Handsontable(container, { cells(row, col) { if ((row === 1 || row === 5) && col === 1) { return { readOnly: true, }; } }});Example
In the example below, the modified cells options overwrite the top-level grid options.
import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector('#example5');const data = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, cells: (row, col) => { return (row === 1 || row === 3) && col === 1 ? { readOnly: true } : {}; }, autoWrapRow: true, autoWrapCol: true,});import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector<HTMLDivElement>('#example5')!;
const data: Handsontable.CellValue[][] = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, cells: (row: number, col: number) => { return (row === 1 || row === 3) && col === 1 ? { readOnly: true } : {}; }, autoWrapRow: true, autoWrapCol: true,});Configuration example
In the example below, some cells are read-only, and some cells are editable:
- By default, all cells are read-only (as set in the top-level grid options).
- For the first column, the mid-level column options overwrite the top-level grid options.
As a result, the first column cells are editable. - For cell
A1(0, 0), the bottom-level cell options overwrite both the mid-level column options, and the top-level grid options.
As a result, cellA1(0, 0) is read-only, despite being part of the editable first column. - For cell
C3(3, 3), thecellsoption overwrites all other options.
As a result, cellC3(3, 3) is editable, despite not being part of the editable first column.
import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector('#example6');const data = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, readOnly: true, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, columns: [ // each cell in the first (by physical index) column is editable { readOnly: false, className: '' }, {}, {}, {}, {}, {}, {}, {}, {}, {}, ], cell: [ // cell (0, 0) is read-only { row: 0, col: 0, readOnly: true }, ], cells: (row, col) => { // cell (2, 2) is editable return row === 2 && col === 2 ? { readOnly: false, className: '' } : {}; }, autoWrapRow: true, autoWrapCol: true,});import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
const container = document.querySelector<HTMLDivElement>('#example6')!;
const data: Handsontable.CellValue[][] = [ ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1'], ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], ['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], ['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], ['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],];
const hot = new Handsontable(container, { licenseKey: 'non-commercial-and-evaluation', data, readOnly: true, width: 'auto', height: 'auto', rowHeaders: true, colHeaders: true, columns: [ // each cell in the first (by physical index) column is editable { readOnly: false, className: '' }, {}, {}, {}, {}, {}, {}, {}, {}, {}, ], cell: [ // cell (0, 0) is read-only { row: 0, col: 0, readOnly: true }, ], cells: (row: number, col: number) => { // cell (2, 2) is editable return row === 2 && col === 2 ? { readOnly: false, className: '' } : {}; }, autoWrapRow: true, autoWrapCol: true,});Related API reference
Configuration options
Core methods
Hooks