Configuration options
Description
Configuration options let you heavily customize your Handsontable instance. For example, you can:
- Enable and disable built-in features
- Enable and configure additional plugins
- Personalize Handsontable’s look
- Adjust Handsontable’s behavior
- Implement your own custom features
To apply configuration options, pass them as a second argument of the Handsontable constructor, using the object literal notation:
Read more on the Configuration options page.
const container = document.getElementById('example');
const hot = new Handsontable(container, { // configuration options, in the object literal notation licenseKey: 'non-commercial-and-evaluation', data: [ ['A1', 'B1', 'C1', 'D1', 'E1'], ['A2', 'B2', 'C2', 'D2', 'E2'], ['A3', 'B3', 'C3', 'D3', 'E3'], ['A4', 'B4', 'C4', 'D4', 'E4'], ['A5', 'B5', 'C5', 'D5', 'E5'], ], 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:
- The entire grid
- Individual columns
- Individual rows
- Individual cells
- Individual grid elements, based on any logic you implement
Read more:
Members
activeHeaderClassName
options.activeHeaderClassName : string
The activeHeaderClassName option lets you add a CSS class name
to every currently-active, currently-selected header (when a whole column or row is selected).
This option can only be set at the grid level.
It has no effect when set in the columns, cells, or cell options.
Read more:
currentRowClassNamecurrentColClassNamecurrentHeaderClassNameinvalidCellClassNamereadOnlyCellClassNamecommentedCellClassNamenoWordWrapClassNameTableClassNameclassName
Default: “ht__active_highlight”
Category: Core
Since: 0.38.2
Example
// add an `ht__active_highlight` CSS class name// to every currently-active, currently-selected headeractiveHeaderClassName: 'ht__active_highlight',allowEmpty
options.allowEmpty : boolean
The allowEmpty option determines whether Handsontable accepts the following values:
nullundefined''
You can set the allowEmpty option to one of the following:
| Setting | Description |
|---|---|
true (default) | - Accept null, undefined and '' values- Mark cells that contain null, undefined or '' values as valid |
false | - Don’t accept null, undefined and '' values- Mark cells that contain null, undefined or '' values with as invalid |
This option can be set at any level of the cascading configuration:
the grid level, the columns level, the cells level, and the cell level.
Default: true
Category: Core
Example
// allow empty values in each cell of the entire gridallowEmpty: true,
// orcolumns: [ { type: 'date', dateFormat: 'DD/MM/YYYY', // allow empty values in each cell of the 'date' column allowEmpty: true }],
// or, using the `cells` optioncells(row, col) { if (col === 2) { return { allowEmpty: false }; }},allowHtml
options.allowHtml : boolean
The allowHtml option configures whether autocomplete
and dropdown cells’ source data
is treated as HTML.
You can set the allowHtml option to one of the following:
| Setting | Description |
|---|---|
false (default) | The source data is not treated as HTML |
true | The source data is treated as HTML |
Warning: Setting the allowHtml option to true can cause serious XSS vulnerabilities.
Read more:
Default: false
Category: Core
Example
columns: [ { // set the `type` of each cell in this column to `autocomplete` type: 'autocomplete', // set options available in every `autocomplete` cell of this column source: ['<strong>foo</strong>', '<strong>bar</strong>'] // use HTML in the `source` list allowHtml: true, },],allowInsertColumn
options.allowInsertColumn : boolean
If set to true, the allowInsertColumn option adds the following menu items to the context menu:
- Insert column left
- Insert column right
This option can only be set at the grid level.
It has no effect when set in the columns, cells, or cell options.
Default: true
Category: Core
Example
// hide the 'Insert column left' and 'Insert column right' menu items from the context menuallowInsertColumn: false,allowInsertRow
options.allowInsertRow : boolean
If set to true, the allowInsertRow option adds the following menu items to the context menu:
- Insert row above
- Insert row below
Default: true
Category: Core
Example
// hide the 'Insert row above' and 'Insert row below' menu items from the context menuallowInsertRow: false,allowInvalid
options.allowInvalid : boolean
The allowInvalid option determines whether Handsontable accepts values
that were marked as invalid by the cell validator.
You can set the allowInvalid option to one of the following:
| Setting | Description |
|---|---|
true (default) | - Accept invalid values- Allow the user to close the cell editor with invalid values- Save invalid values into the data source |
false | - Don’t accept invalid values- Don’t allow the user to close the cell editor with invalid values- Don’t save invalid values into the data source |
Setting the allowInvalid option to false can be useful when used with the Autocomplete strict mode.
Read more:
Default: true
Category: Core
Example
// don't accept `invalid` values// don't allow the user to close the cell editor// don't save `invalid` values into the data sourceallowInvalid: false,allowRemoveColumn
options.allowRemoveColumn : boolean
If set to true, the allowRemoveColumn option adds the following menu items to the context menu:
- Remove column
This option can only be set at the grid level.
It has no effect when set in the columns, cells, or cell options.
Read more:
Default: true
Category: Core
Example
// hide the 'Remove column' menu item from the context menuallowRemoveColumn: false,allowRemoveRow
options.allowRemoveRow : boolean
If set to true, the allowRemoveRow option adds the following menu items to the context menu:
- Remove row
Read more:
Default: true
Category: Core
Example
// hide the 'Remove row' menu item from the context menuallowRemoveRow: false,ariaTags
options.ariaTags : boolean
If set to true, the accessibility-related ARIA tags will be added to the table. If set to false, they
will be omitted.
Defaults to true.
Default: true
Category: Core
Since: 14.0.0
autoColumnSize
options.autoColumnSize : object | boolean
The autoColumnSize option configures the AutoColumnSize plugin.
You can set the autoColumnSize option to one of the following:
| Setting | Description |
|---|---|
false | Disable the AutoColumnSize plugin |
true | Enable the AutoColumnSize plugin with the default configuration |
| An object | Enable the AutoColumnSize plugin and modify the plugin options |
If you set the autoColumnSize option to an object, you can set the following AutoColumnSize plugin options:
| Property | Possible values | Description |
|---|---|---|
syncLimit | A number | A percentage string | The number/percentage of columns to keep in sync (default: 50) |
useHeaders | true | false | When calculating column widths:true: use column headersfalse: don’t use column headers |
samplingRatio | A number | The number of samples of the same length to be used in column width calculations |
allowSampleDuplicates | true | false | When calculating column widths:true: Allow duplicate samplesfalse: Don’t allow duplicate samples |
By default, the autoColumnSize option is set to undefined,
but the AutoColumnSize plugin acts as enabled.
To disable the AutoColumnSize plugin completely,
set the autoColumnSize option to false.
Using the colWidths option forcibly disables the AutoColumnSize plugin.
Read more:
Default: undefined
Category: AutoColumnSize
Example
autoColumnSize: { // keep 40% of columns in sync (the rest of columns: async) syncLimit: '40%', // when calculating column widths, use column headers useHeaders: true, // when calculating column widths, use 10 samples of the same length samplingRatio: 10, // when calculating column widths, allow duplicate samples allowSampleDuplicates: true},autoRowSize
options.autoRowSize : object | boolean
The autoRowSize option configures the AutoRowSize plugin.
You can set the autoRowSize option to one of the following:
| Setting | Description |
|---|---|
false | Disable the AutoRowSize plugin |
true | Enable the AutoRowSize plugin with the default configuration |
| An object | Enable the AutoRowSize plugin and modify the plugin options |
To give Handsontable’s scrollbar a proper size, set the autoRowSize option to true.
If you set the autoRowSize option to an object, you can set the following AutoRowSize plugin options:
| Property | Possible values | Description |
|---|---|---|
syncLimit | A number | A percentage string | The number/percentage of rows to keep in sync (default: 500) |
Using the rowHeights option forcibly disables the AutoRowSize plugin.
Read more:
Default: undefined
Category: AutoRowSize
Example
autoRowSize: { // keep 40% of rows in sync (the rest of rows: async) syncLimit: '40%'},autoWrapCol
options.autoWrapCol : boolean
| Setting | Description |
|---|---|
false (default) | When you select a bottom-most cell, pressing ↓ doesn’t do anything. When you select a top-most cell, pressing ↑ doesn’t do anything. |
true | When you select a bottom-most cell, pressing ↓ takes you to the top-most cell of the next column. When you select a top-most cell, pressing ↑ takes you to the bottom-most cell of the previous column. |
Default: false
Category: Core
Example
// when you select a bottom-most cell, pressing ⬇ doesn't do anything// when you select a top-most cell, pressing ⬆ doesn't do anythingautoWrapCol: false, // default setting
// when you select a bottom-most cell, pressing ⬇ takes you to the top-most cell of the next column// when you select a top-most cell, pressing ⬆ takes you to the bottom-most cell of the previous columnautoWrapCol: true,autoWrapRow
options.autoWrapRow : boolean
| Setting | Description |
|---|---|
false (default) | When you select the first cell of a row, pressing ←* (or Shift+Tab**) doesn’t do anything. When you select the last cell of a row, pressing →* (or Tab**) doesn’t do anything. |
true | When you select the first cell of a row, pressing ←* (or Shift+Tab**) takes you to the last cell of the row above. When you select the last cell of a row, pressing →* (or Tab**) takes you to the first cell of the row below. |
* The exact key depends on your layoutDirection configuration.
** Unless tabNavigation is set to false.
Default: false
Category: Core
Example
// when you select the first cell of a row, pressing ⬅ (or Shift+Tab) doesn't do anything// when you select the last cell of a row, pressing ➡ (or Tab) doesn't do anythingautoWrapRow: false, // default setting
// when you select the first cell of a row, pressing ⬅ (or Shift+Tab) takes you to the last cell of the row above// when you select the last cell of a row, pressing ➡ (or Tab) takes you to the first cell of the row belowautoWrapRow: true,bindRowsWithHeaders
options.bindRowsWithHeaders : boolean | string
The bindRowsWithHeaders option configures the BindRowsWithHeaders plugin.
When enabled, each row stays permanently linked to its row header label, regardless of row sorting or row moving. Normally, row headers display the visual row index and update as rows are reordered; with this plugin enabled, the header travels with the data row it was originally assigned to.
You can set the bindRowsWithHeaders option to one of the following:
| Setting | Description |
|---|---|
false | Disable the the BindRowsWithHeaders plugin |
true | Enable the the BindRowsWithHeaders plugin |
This option can only be set at the grid level.
It has no effect when set in the columns, cells, or cell options.
Read more:
Default: undefined
Category: BindRowsWithHeaders
Example
// enable the `BindRowsWithHeaders` pluginbindRowsWithHeaders: truecell
options.cell : Array<Array>
The cell option lets you apply configuration options to individual cells.
The cell option overwrites the top-level grid options,
and the columns options.
Read more:
Default: []
Category: Core
Example
// set the `cell` option to an array of objectscell: [ // make the cell with coordinates (0, 0) read-only { row: 0, col: 0, readOnly: true }],cells
options.cells : function
The cells option lets you apply any other configuration options to
individual grid elements (columns, rows, cells), based on any logic you implement.
The cells option overwrites all other options (including options set by columns and cell).
It takes the following parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
row | Yes | Number | A physical row index |
column | Yes | Number | A physical column index |
prop | No | String | Number | If data is set to an array of arrays, prop is the same number as column.If data is set to an array of objects, prop is a property name for the column’s data object. |
Read more:
- Configuration options: Implementing custom logic
- Configuration options: Setting row options
columnscell
Default: undefined
Category: Core
Example
// set the `cells` option to your custom functioncells(row, column, prop) { const cellProperties = { readOnly: false }; const visualRowIndex = this.instance.toVisualRow(row); const visualColIndex = this.instance.toVisualColumn(column);
if (visualRowIndex === 0 && visualColIndex === 0) { cellProperties.readOnly = true; } else { cellProperties.readOnly = false; }
return cellProperties;},checkedTemplate
options.checkedTemplate : boolean | string | number
The checkedTemplate option lets you configure what value
a checked checkbox cell has.
You can set the checkedTemplate option to one of the following:
| Setting | Description |
|---|---|
true (default) | If a checkbox cell is checked,the getDataAtCell method for this cell returns true |
| A string | If a checkbox cell is checked,the getDataAtCell method for this cell returns a string of your choice |
This option can be set at any level of the cascading configuration:
the grid level, the columns level, the cells level, and the cell level.
Read more:
Default: true
Category: Core
Example
columns: [ { // set the `type` of each cell in this column to `checkbox` // when checked, the cell's value is `true` // when unchecked, the cell's value is `false` type: 'checkbox', }, { // set the `type` of each cell in this column to `checkbox` type: 'checkbox', // when checked, the cell's value is `'Yes'` checkedTemplate: 'Yes', // when unchecked, the cell's value is `'No'` uncheckedTemplate: 'No' }],className
options.className : string | Array<string>
The className option lets you add CSS class names to every currently-selected element.
You can set the className option to one of the following:
| Setting | Description |
|---|---|
| A string | Add a single CSS class name to every currently-selected element |
| An array of strings | Add multiple CSS class names to every currently-selected element |
To apply different CSS class names on different levels, use Handsontable’s cascading configuration.
Read more:
- Configuration options: Cascading configuration
currentRowClassNamecurrentColClassNamecurrentHeaderClassNameactiveHeaderClassNameinvalidCellClassNameplaceholderCellClassNamecommentedCellClassNamenoWordWrapClassNamereadOnlyCellClassNameTableClassName
Default: undefined
Category: Core
Example
// add a `your-class-name` CSS class name// to every currently-selected elementclassName: 'your-class-name',
// add `first-class-name` and `second-class-name` CSS class names// to every currently-selected elementclassName: ['first-class-name', 'second-class-name'],colHeaders
options.colHeaders : boolean | Array<string> | function
The colHeaders option configures your grid’s column headers.
You can set the colHeaders option to one of the following:
| Setting | Description |
|---|---|
true | Enable the default column headers (‘A’, ‘B’, ‘C’, …) |
false | Disable column headers |
| An array | Define your own column headers (e.g. ['One', 'Two', 'Three', ...]) |
| A function | Define your own column headers, using a function |
Read more:
Default: null
Category: Core
Example
// enable the default column headerscolHeaders: true,
// set your own column headerscolHeaders: ['One', 'Two', 'Three'],
// set your own column headers, using a functioncolHeaders: function(visualColumnIndex) { return `${visualColumnIndex} + : AB`;},collapsibleColumns
options.collapsibleColumns : boolean | Array<object>
The collapsibleColumns option configures the CollapsibleColumns plugin.
You can set the collapsibleColumns option to one of the following:
| Setting | Description |
|---|---|
false | Disable the CollapsibleColumns plugin |
true | Enable the CollapsibleColumns plugin |
| An array of objects | Enable the CollapsibleColumns plugin for selected column headers |
When using an array of objects, specify the header to make collapsible using row and col.
The row value is a negative integer that counts header levels from the bottom of the header area:
-1 is the header row closest to the data, -2 is one level above, and so on.
This option requires the nestedHeaders plugin to be configured.
This option can only be set at the grid level.
It has no effect when set in the columns, cells, or cell options.
Read more:
Default: undefined
Category: CollapsibleColumns
Example
// enable column collapsing for all headerscollapsibleColumns: true,
// enable column collapsing for selected headerscollapsibleColumns: [ {row: -4, col: 1, collapsible: true}, {row: -3, col: 5, collapsible: true}],columnHeaderHeight
options.columnHeaderHeight : number | Array<number>
The columnHeaderHeight option configures the height of column headers.
You can set the columnHeaderHeight option to one of the following:
| Setting | Description |
|---|---|
| A number | Set the same height for every column header |
| An array | Set different heights for individual column headers |
Default: undefined
Category: Core
Example
// set the same height for every column headercolumnHeaderHeight: 25,
// set different heights for individual column headerscolumnHeaderHeight: [25, 30, 55],columns
options.columns : Array<object> | function
The columns option lets you apply any other configuration options to individual columns (or ranges of columns).
You can set the columns option to one of the following:
- An array of objects (each object represents one column)
- A function that returns an array of objects
The columns option overwrites the top-level grid options.
When you use columns, the startCols, minCols, and maxCols options are ignored.
Read more:
Default: undefined
Category: Core
Example
// set the `columns` option to an array of objects// each object represents one columncolumns: [ { // column options for the first (by physical index) column type: 'numeric', numericFormat: { pattern: '0,0.00 $' } }, { // column options for the second (by physical index) column type: 'text', readOnly: true }],
// or set the `columns` option to a function, based on physical indexescolumns(index) { return { type: index > 0 ? 'numeric' : 'text', readOnly: index < 1 }}columnSorting
options.columnSorting : boolean | object
The columnSorting option configures the ColumnSorting plugin.
You can set the columnSorting option to one of the following:
| Setting | Description |
|---|---|
true | Enable the ColumnSorting plugin with the default configuration |
false | Disable the ColumnSorting plugin |
| An object | - Enable the ColumnSorting plugin- Modify the ColumnSorting plugin options |
If you set the columnSorting option to an object,
you can set the following ColumnSorting plugin options:
| Option | Possible settings |
|---|---|
indicator | true: Display the arrow icon in the column header, to indicate a sortable columnfalse: Don’t display the arrow icon in the column header |
headerAction | true: Enable clicking on the column header to sort the columnfalse: Disable clicking on the column header to sort the column |
sortEmptyCells | true: Sort empty cells as wellfalse: Place empty cells at the end |
compareFunctionFactory | A custom compare function |
If you set the columnSorting option to an object,
you can also sort individual columns at Handsontable’s initialization.
In the columnSorting object, add an object named initialConfig,
with the following properties:
| Option | Possible settings | Description |
|---|---|---|
column | A number | The index of the column that you want to sort at initialization |
sortOrder | 'asc' | 'desc' | The sorting order:'asc': ascending'desc': descending |
Read more:
Default: undefined
Category: ColumnSorting
Example
// enable the `ColumnSorting` plugincolumnSorting: true
// enable the `ColumnSorting` plugin with custom configurationcolumnSorting: { // sort empty cells as well sortEmptyCells: true, // display the arrow icon in the column header indicator: true, // disable clicking on the column header to sort the column headerAction: false, // add a custom compare function compareFunctionFactory(sortOrder, columnMeta) { return function(value, nextValue) { // some value comparisons which will return -1, 0 or 1... } }}
// enable the `ColumnSorting` plugin with an initial sort order:// sort column 1 in ascending order at initializationcolumnSorting: { initialConfig: { column: 1, sortOrder: 'asc' }}columnSummary
options.columnSummary : Array<object> | function
The columnSummary option configures the ColumnSummary plugin.
You can set the columnSummary option to an array of objects.
Each object configures a single column summary, using the following properties:
| Property | Possible values | Description |
|---|---|---|
sourceColumn | A number | Column to summarize |
ranges | An array | Ranges of rows to summarize |
type | 'sum' | 'min' | 'max' | 'count' | 'average' | 'custom' | Summary function |
destinationRow | A number | Destination cell’s row coordinate |
destinationColumn | A number | Destination cell’s column coordinate |
forceNumeric | true | false | Treat non-numerics as numerics |
reversedRowCoords | true | false | Reverse row coordinates |
suppressDataTypeErrors | true | false | Suppress data type errors |
readOnly | true | false | Make summary cell read-only |
roundFloat | true | false | A number | Round summary result |
customFunction | A function | Custom summary function |
Read more:
Default: undefined
Category: ColumnSummary
Example
columnSummary: [ { sourceColumn: 0, ranges: [ [0, 2], [4], [6, 8] ], type: 'custom', destinationRow: 4, destinationColumn: 1, forceNumeric: true, reversedRowCoords: true, suppressDataTypeErrors: false, readOnly: true, roundFloat: false, customFunction(endpoint) { return 100; } }],colWidths
options.colWidths : number | Array<number> | string | Array<string> | Array<undefined> | function
The colWidths option sets columns’ widths, in pixels.
The default column width is 50px. To change it, set the colWidths option to one of the following:
| Setting | Description | Example |
|---|---|---|
| A number | Set the same width for every column | colWidths: 100 |
| A string | Set the same width for every column | colWidths: '100px' |
| An array | Set widths separately for each column | colWidths: [100, 120, undefined] |
| A function | Set column widths dynamically, on each render | colWidths(visualColumnIndex) { return visualColumnIndex * 10; } |
undefined | Used by the modifyColWidth hook, to detect column width changes. | colWidths: undefined |
Setting colWidths even for a single column disables the AutoColumnSize plugin
for all columns. For this reason, if you use colWidths, we recommend you set a width for each one
of your columns. Otherwise, every column with an undefined width defaults back to 50px,
which may cut longer columns names.
Read more:
Default: undefined
Category: Core
Example
// set every column's width to 100pxcolWidths: 100,
// set every column's width to 100pxcolWidths: '100px',
// set the first (by visual index) column's width to 100// set the second (by visual index) column's width to 120// set the third (by visual index) column's width to `undefined`, so that it defaults to 50px// set any other column's width to the default 50px (note that longer cell values and column names can get cut)colWidths: [100, 120, undefined],
// set each column's width individually, using a functioncolWidths(visualColumnIndex) { return visualColumnIndex * 10;},commentedCellClassName
options.commentedCellClassName : string
The commentedCellClassName option lets you add a CSS class name to cells
that have comments.
Read more:
- Comments
commentsreadOnlyCellClassNamecurrentRowClassNamecurrentHeaderClassNameactiveHeaderClassNameinvalidCellClassNameplaceholderCellClassNamereadOnlyCellClassNamenoWordWrapClassNameTableClassNameclassName
Default: “htCommentCell”
Category: Core
Example
// add a `has-comment` CSS class name// to each cell that has a commentcommentedCellClassName: 'has-comment',comments
options.comments : boolean | Array<object>
The comments option configures the Comments plugin.
You can set the comments option to one of the following:
| Setting | Description |
|---|---|
true | - Enable the Comments plugin- Add comment menu items to the context menu |
false | Disable the Comments plugin |
| An object | - Enable the Comments plugin- Add comment menu items to the context menu - Configure comment settings |
If you set the comments option to an object, you can configure the following comment options:
| Option | Possible settings | Description |
|---|---|---|
displayDelay | A number (default: 250) | Display comments after a delay (in milliseconds) |
readOnly | true | false (default) | true: Make comments read-only |
style | An object | Set comment boxes’ width and height (in pixels) |
Read more:
Default: false
Category: Comments
Example
// enable the `Comments` plugincomments: true,
// enable the `Comments` plugin// and configure its settingscomments: { // display all comments with a 1-second delay displayDelay: 1000, // make all comments read-only readOnly: true, // set the default size of all comment boxes style: { width: 300, height: 100 }}contextMenu
options.contextMenu : boolean | Array<string> | object
The contextMenu option configures the ContextMenu plugin.
You can set the contextMenu option to one of the following:
| Setting | Description |
|---|---|
false | Disable the ContextMenu plugin |
true | - Enable the ContextMenu plugin- Use the default context menu options |
| An array | - Enable the ContextMenu plugin- Modify individual context menu options |
| An object | - Enable the ContextMenu plugin- Apply a custom context menu configuration |
Read more:
- Context menu
- Context menu: Context menu with default options
- Context menu: Context menu with specific options
- Context menu: Context menu with fully custom configuration options
- Plugins:
ContextMenu
Default: undefined
Category: ContextMenu
Example
// enable the `ContextMenu` plugin// use the default context menu optionscontextMenu: true,
// enable the `ContextMenu` plugin// and modify individual context menu optionscontextMenu: ['row_above', 'row_below', '---------', 'undo', 'redo'],
// enable the `ContextMenu` plugin// and apply a custom context menu configurationcontextMenu: { items: { 'option1': { name: 'Option 1' }, 'option2': { name: 'Option 2', submenu: { items: [ { key: 'option2:suboption1', name: 'Suboption 1', callback: function(key, options) { ... } }, ... ] } } }},copyable
options.copyable : boolean
The copyable option determines whether a cell’s value can be copied to the clipboard or not.
You can set the copyable option to one of the following:
| Setting | Description |
|---|---|
true (default) | - On pressing Ctrl/Cmd+C, add the cell’s value to the clipboard |
false(default for the password cell type) | - On pressing Ctrl/Cmd+C, add an empty string ("") to the clipboard |
Read more:
Default: true
Category: Core
Example
// enable copying for each cell of the entire gridcopyable: true,
// enable copying for individual columnscolumns: [ { // enable copying for each cell of this column copyable: true }, { // disable copying for each cell of this column copyable: false }]
// enable copying for specific cellscell: [ { col: 0, row: 0, // disable copying for cell (0, 0) copyable: false, }],copyPaste
options.copyPaste : object | boolean
The copyPaste option configures the CopyPaste plugin.
You can set the copyPaste option to one of the following:
| Setting | Description |
|---|---|
true (default) | Enable the CopyPaste plugin with the default configuration |
false | Disable the CopyPaste plugin |
| An object | - Enable the CopyPaste plugin- Modify the CopyPaste plugin options |
copyPaste: Additional options
If you set the copyPaste option to an object, you can set the following CopyPaste plugin options:
| Option | Possible settings | Description |
|---|---|---|
columnsLimit | A number (default: Infinity) | The maximum number of columns that can be copied |
rowsLimit | A number (default: Infinity) | The maximum number of columns that can be copied |
pasteMode | 'overwrite' | 'shift_down' | 'shift_right' | When pasting:'overwrite': overwrite the currently-selected cells'shift_down': move the currently-selected cells down'shift_right': move the currently-selected cells to the right |
copyColumnHeaders | Boolean (default: false) | true: add a context menu option for copying cells along with their nearest column headers |
copyColumnGroupHeaders | Boolean (default: false) | true: add a context menu option for copying cells along with all their related columns headers |
copyColumnHeadersOnly | Boolean (default: false) | true: add a context menu option for copying column headers nearest to the selected cells (without copying cells) |
uiContainer | An HTML element | The UI container for the secondary focusable element |
Read more:
Default: true
Category: CopyPaste
Example
// enable the plugin with the default configurationcopyPaste: true // set by default
// disable the plugincopyPaste: false,
// enable the plugin with a custom configurationcopyPaste: { // set a maximum number of columns that can be copied columnsLimit: 25,
// set a maximum number of rows that can be copied rowsLimit: 50,
// set the paste behavior pasteMode: 'shift_down',
// add the option to copy cells along with their nearest column headers copyColumnHeaders: true,
// add the option to copy cells along with all their related columns headers copyColumnGroupHeaders: true,
// add the option to copy just column headers (without copying cells) copyColumnHeadersOnly: true,
// set a UI container uiContainer: document.body,},correctFormat Deprecated
options.correctFormat : boolean
The `correctFormat` option configures whether incorrectly-formatted times and dates are amended or not.When the user enters dates and times, Handsontable can automatically adjust their format
to match the dateFormat and timeFormat settings.
You can set the correctFormat option to one of the following:
| Setting | Description |
|---|---|
false (default) | Don’t correct the format of the entered date or time (treat the entered date or time as invalid) |
true | Correct the format of the entered date or time to match the dateFormat or timeFormat settings |
Read more:
Default: false
Category: Core
Example
columns: [ { // set the `type` of each cell in this column to `date` type: 'date', // for every `date` cell of this column, set the date format to `YYYY-MM-DD` dateFormat: 'YYYY-MM-DD', // enforce the `YYYY-MM-DD` date format correctFormat: true },
{ // set the `type` of each cell in this column to `time` type: 'time', // for every `time` cell of this column, set the time format to `h:mm:ss a` timeFormat: 'h:mm:ss a', // enforce the `h:mm:ss a` time format correctFormat: true },],currentColClassName
options.currentColClassName : string
The currentColClassName option lets you add a CSS class name
to each cell of the currently-visible, currently-selected columns.
Read more:
currentRowClassNamecurrentHeaderClassNameactiveHeaderClassNameinvalidCellClassNameplaceholderCellClassNamereadOnlyCellClassNamecommentedCellClassNamenoWordWrapClassNameTableClassNameclassName
Default: undefined
Category: Core
Example
// add a `your-class-name` CSS class name// to each cell of the currently-visible, currently-selected columnscurrentColClassName: 'your-class-name',currentHeaderClassName
options.currentHeaderClassName : string
The currentHeaderClassName option lets you add a CSS class name
to every currently-visible, currently-selected header.
Read more:
currentRowClassNamecurrentColClassNameactiveHeaderClassNameinvalidCellClassNamereadOnlyCellClassNamecommentedCellClassNamenoWordWrapClassNameTableClassNameclassName
Default: “ht__highlight”
Category: Core
Example
// add an `ht__highlight` CSS class name// to every currently-visible, currently-selected headercurrentHeaderClassName: 'ht__highlight',currentRowClassName
options.currentRowClassName : string
The currentRowClassName option lets you add a CSS class name
to each cell of the currently-visible, currently-selected rows.
Read more:
currentColClassNamecurrentHeaderClassNameactiveHeaderClassNameinvalidCellClassNameplaceholderCellClassNamereadOnlyCellClassNamecommentedCellClassNamenoWordWrapClassNameTableClassNameclassName
Default: undefined
Category: Core
Example
// add a `your-class-name` CSS class name// to each cell of the currently-visible, currently-selected rowscurrentRowClassName: 'your-class-name',customBorders
options.customBorders : boolean | Array<object>
The customBorders option configures the CustomBorders plugin.
To enable the CustomBorders plugin
(and add its menu items to the context menu),
set the customBorders option to true.
To enable the CustomBorders plugin
and add a predefined border around a particular cell,
set the customBorders option to an array of objects.
Each object represents a border configuration for one cell, and has the following properties:
| Property | Sub-properties | Types | Description |
|---|---|---|---|
row | - | row: Number | The cell’s row coordinate. |
col | - | col: Number | The cell’s column coordinate. |
start | widthcolorstyle | width: Numbercolor: Stringstyle: String | If the layout direction is LTR (default): start sets the width (width), color (color) and style (style) of the left-hand border.If the layout direction is RTL: start sets the width (width), color (color) and style (style) of the right-hand border. |
end | widthcolorstyle | width: Numbercolor: Stringstyle: String | If the layout direction is LTR (default): end sets the width (width), color (color) and style (style) of the right-hand border.If the layout direction is RTL: end sets the width (width), color (color) and style (style) of the left-hand border. |
top | widthcolorstyle | width: Numbercolor: Stringstyle: String | Sets the width (width), color (color) and style (style) of the top border. |
bottom | widthcolorstyle | width: Numbercolor: Stringstyle: String | Sets the width (width), color (color) and style (style) of the bottom border. |
To enable the CustomBorders plugin
and add a predefined border around a range of cells,
set the customBorders option to an array of objects.
Each object represents a border configuration for a single range of cells, and has the following properties:
| Property | Sub-properties | Types | Description |
|---|---|---|---|
range | from {row, col}to {row, col} | from: Objectto: Objectrow: Numbercol: Number | If the layout direction is LTR (default): - from selects the range’s top-left corner.- to selects the range’s bottom-right corner.If the layout direction is RTL: - from selects the range’s top-right corner.- to selects the range’s bottom-left corner. |
start | widthcolorstyle | width: Numbercolor: Stringstyle: String | If the layout direction is LTR (default): start sets the width (width), color (color) and style (style) of the left-hand border.If the layout direction is RTL: start sets the width (width), color (color) and style (style) of the right-hand border. |
end | widthcolorstyle | width: Numbercolor: Stringstyle: String | If the layout direction is LTR (default): end sets the width (width), color (color) and style (style) of the right-hand border.If the layout direction is RTL: end sets the width (width), color (color) and style (style) of the left-hand border. |
top | widthcolorstyle | width: Numbercolor: Stringstyle: String | Sets the width (width), color (color) and style (style) of the top border. |
bottom | widthcolorstyle | width: Numbercolor: Stringstyle: String | Sets the width (width), color (color) and style (style) of the bottom border. |
Read more:
- Formatting cells: Custom cell borders
- Context menu
- Plugins:
CustomBorders - Layout direction
layoutDirection
Default: false
Category: CustomBorders
Example
// enable the `CustomBorders` plugincustomBorders: true,
// enable the `CustomBorders` plugin// and add a predefined border for a particular cellcustomBorders: [ // add an object with a border configuration for one cell { // set the cell's row coordinate row: 2, // set the cell's column coordinate col: 2, // set the left/right border's width and color start: { width: 2, color: 'red' }, // set the right/left border's width, color and style end: { width: 1, color: 'green', style: 'dashed' }, // set the top border's width and color top: '', // set the bottom border's width and color bottom: '' }],
// enable the `CustomBorders` plugin// and add a predefined border for a range of cellscustomBorders: [ // add an object with a border configuration for one range of cells { // select a range of cells range: { // set the range's top-left corner from: { row: 1, col: 1 }, // set the range's bottom-right corner to: { row: 3, col: 4 } }, // set the left/right border's width, color and style start: { width: 2, color: 'red', style: 'dashed' }, // set the right/left border's width and color end: {}, // set the top border's width and color top: {}, // set the bottom border's width and color bottom: {} }],data
options.data : Array<Array> | Array<object>
The data option sets the initial data of your Handsontable instance.
Handsontable’s data is bound to your source data by reference (i.e. when you edit Handsontable’s data, your source data alters as well).
You can set the data option:
- Either to an array of arrays.
- Or to an array of objects.
If you don’t set the data option (or set it to null), Handsontable renders as an empty 5x5 grid by default.
When used inside the columns option, data has a different meaning: it acts as a property name
(or a dot-separated path) pointing to the field in each data row object that this column reads from and writes to.
In this context, data is not the full dataset but a column accessor string.
Read more:
Default: undefined
Category: Core
Example
// as an array of arraysdata: [ ['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'J']]
// as an array of objectsdata: [ {id: 1, name: 'Ted Right'}, {id: 2, name: 'Frank Honest'}, {id: 3, name: 'Joan Well'}, {id: 4, name: 'Gail Polite'}, {id: 5, name: 'Michael Fair'},]
// as a column accessor inside `columns`columns: [ { data: 'id' }, { data: 'name' }]dataDotNotation
options.dataDotNotation : boolean
If true, Handsontable will interpret the dots in the columns mapping as a nested object path. If your dataset contains
the dots in the object keys and you don’t want Handsontable to interpret them as a nested object path, set this option to false.
The option only works when defined in the global table settings.
Default: true
Category: Core
Since: 14.4.0
Example
// All dots are interpreted as nested object pathsdataDotNotation: true,data: [ { id: 1, name: { first: 'Ted', last: 'Right' }, user: { address: '1234 Any Street' } },],columns={[ { data: 'name.first' }, { data: 'user.address' },]},// All dots are interpreted as simple object keysdataDotNotation: false,data: [ { id: 1, 'name.first': 'Ted', 'user.address': '1234 Any Street' },],columns={[ { data: 'name.first' }, { data: 'user.address' },]},dataProvider
options.dataProvider : object
When set, the table loads data from an async provider (e.g. a REST API) instead of a static data array.
Use the object form with every key defined: rowId, fetchRows, onRowsCreate, onRowsUpdate,
and onRowsRemove. All five are required on that object so paging, row identity, and create, update, and remove
map cleanly to your backend. Pair with pagination for server-side paging.
Valid cell edits apply at once; if onRowsUpdate fails or beforeRowsMutation blocks the update, affected cells roll back.
Default: undefined
Category: Core
Since: 17.1.0
Example
dataProvider: { rowId: 'id', fetchRows: async (queryParameters, { signal }) => { const { page, pageSize, sort, filters } = queryParameters; const params = new URLSearchParams({ page: String(page), pageSize: String(pageSize) });
if (sort) { params.set('sortBy', sort.prop); params.set('sortDir', sort.order); }
const res = await fetch(`/api/products?${params}`, { signal }); const json = await res.json();
return { rows: json.data, totalRows: json.total }; }, onRowsCreate: async ({ position, referenceRowId, rowsAmount }) => { ... }, onRowsUpdate: async (rows) => { ... }, onRowsRemove: async (rowIds) => { ... },},dataSchema
options.dataSchema : object | function
When the data option is set to an array of objects
(or is empty), the dataSchema option defines the structure of new rows.
Using the dataSchema option, you can start out with an empty grid.
You can set the dataSchema option to one of the following:
- An object
- A function
Read more:
- Binding to data: Array of objects with custom data schema
- Binding to data: Function data source and schema
data
Default: undefined
Category: Core
Example
// with `dataSchema`, you can start with an empty griddata: null,dataSchema: {id: null, name: {first: null, last: null}, address: null},colHeaders: ['ID', 'First Name', 'Last Name', 'Address'],columns: [ {data: 'id'}, {data: 'name.first'}, {data: 'name.last'}, {data: 'address'}],startRows: 5,minSpareRows: 1dateFormat
options.dateFormat : string | object
Configures the date format for date cells. Accepts either a string (legacy, for date
cells) or an object of Intl.DateTimeFormat
options (for intl-date cells).
Object form (Intl.DateTimeFormat options):
The object form is supported only when the cell type is intl-date. The locale is controlled separately via the locale option.
Style shortcuts:
| Property | Possible values | Description |
|---|---|---|
dateStyle | 'full', 'long', 'medium', 'short' | Date formatting style (expands to weekday, day, month, year, era) |
timeStyle | 'full', 'long', 'medium', 'short' | Time formatting style (expands to hour, minute, second, timeZoneName) |
Date-time component options:
| Property | Possible values | Description |
|---|---|---|
weekday | 'long', 'short', 'narrow' | Representation of the weekday |
era | 'long', 'short', 'narrow' | Representation of the era |
year | 'numeric', '2-digit' | Representation of the year |
month | 'numeric', '2-digit', 'long', 'short', 'narrow' | Representation of the month |
day | 'numeric', '2-digit' | Representation of the day |
dayPeriod | 'narrow', 'short', 'long' | Day period (e.g. “am”, “noon”) |
hour | 'numeric', '2-digit' | Representation of the hour |
minute | 'numeric', '2-digit' | Representation of the minute |
second | 'numeric', '2-digit' | Representation of the second |
fractionalSecondDigits | 1, 2, 3 | Fraction-of-second digits |
timeZoneName | 'long', 'short', 'shortOffset', 'longOffset', 'shortGeneric', 'longGeneric' | Time zone display |
Locale and other options:
| Property | Possible values | Description |
|---|---|---|
localeMatcher | 'best fit' (default), 'lookup' | Locale matching algorithm |
calendar | 'chinese', 'gregory', 'persian', etc. | Calendar to use |
numberingSystem | 'latn', 'arab', 'hans', etc. | Numbering system |
timeZone | IANA time zone (e.g. 'UTC', 'America/New_York') | Time zone for formatting |
hour12 | true, false | Use 12-hour vs 24-hour time |
hourCycle | 'h11', 'h12', 'h23', 'h24' | Hour cycle |
formatMatcher | 'basic', 'best fit' (default) | Format matching algorithm |
For complete reference, see MDN: Intl.DateTimeFormat.
Read more:
Deprecated: string form
Passing a string (e.g. 'DD/MM/YYYY', 'YYYY-MM-DD') is deprecated and works only with the date cell type.
Migrate to the intl-date cell type and pass an Intl.DateTimeFormat options object.
Migration example:
// Before (deprecated)columns: [{ type: 'date', dateFormat: 'YYYY-MM-DD'}]
// After (recommended)columns: [{ type: 'intl-date', locale: 'en-US', dateFormat: { year: 'numeric', month: '2-digit', day: '2-digit' }}]Default: “DD/MM/YYYY”
Category: Core
Example
// intl-date cell type with Intl optionscolumns: [ { type: 'intl-date', locale: 'en-US', dateFormat: { dateStyle: 'short' } }]Example
// Legacy: date cell type with string format (deprecated)columns: [ { type: 'date', dateFormat: 'YYYY-MM-DD' }]datePickerConfig Deprecated
options.datePickerConfig : object
The `datePickerConfig` option configures the `date` [cell editor](/docs/javascript-data-grid/cell-editor/)'s date picker, which uses an external dependency: [Pikaday](https://github.com/Pikaday/Pikaday/tree/1.8.2).You can set the datePickerConfig option to an object with any of the available Pikaday options,
except for the following, which are always overwritten by the date cell editor:
boundcontainerfieldtrigger
If the datePickerConfig option is not defined, the date cell editor overwrites the following Pikaday options as well:
| Pikaday option | Handsontable’s setting |
|---|---|
format | 'DD/MM/YYYY' |
reposition | false |
Read more:
Default: undefined
Category: Core
defaultDate
options.defaultDate : string
The defaultDate option configures the date pre-selected in the date picker editor
when opening an empty date cell for editing.
The option accepts a string in ISO 8601 format (YYYY-MM-DD).
This option can be set at any level of the cascading configuration:
the grid level, the columns level, the cells level, and the cell level.
Read more:
Default: undefined
Category: Core
Example
columns: [ { type: 'date', defaultDate: '2015-02-02' }],dialog
options.dialog : boolean | object
The dialog option configures the Dialog plugin.
You can set the dialog option to one of the following:
dialog: Additional options
| Option | Possible settings | Description |
|---|---|---|
template | Object with the template configuration (default: null). | The template of the dialog allows to use prebuild templates |
template.type | The type of the template (‘confirm’) | The type of the template |
template.title | The title of the template | The title of the template |
template.description | The description of the template | The description of the template |
template.buttons | Array of objects with the buttons configuration (default: []) | The buttons of the template |
template.buttons.text | The text of the button | The text of the button |
template.buttons.type | The type of the button (‘primary' | 'secondary’) |
template.buttons.callback | The callback function to trigger when the button is clicked | The callback function to trigger when the button is clicked |
content | A string, HTMLElement or DocumentFragment (default: '') | The content of the dialog |
customClassName | A string (default: '') | The custom class name of the dialog |
background | One of the options: 'solid' or 'semi-transparent' (default: 'solid') | The background of the dialog |
contentBackground | Boolean (default: false) | Whether to show the content background |
animation | Boolean (default: true) | Whether to show the animation |
closable | Boolean (default: false) | Whether to make the dialog closable |
a11y | Object with accessibility options (default: { role: 'dialog', ariaLabel: 'Dialog', ariaLabelledby: '', ariaDescribedby: '' }) | Accessibility options for the dialog |
a11y.role | The role of the dialog (‘dialog' | 'alertdialog’) |
a11y.ariaLabel | The label of the dialog | The label of the dialog |
a11y.ariaLabelledby | The ID of the element that labels the dialog | The ID of the element that labels the dialog |
a11y.ariaDescribedby | The ID of the element that describes the dialog | The ID of the element that describes the dialog |
Read more:
Default: false
Category: Dialog
Since: 16.1.0
Example
// enable the Dialog plugin with default optiondialog: true,
// enable the Dialog plugin with custom configurationdialog: { content: 'Dialog content', customClassName: 'custom-dialog', background: 'semi-transparent', contentBackground: false, animation: false, closable: true, a11y: { role: 'dialog', ariaLabel: 'Dialog', ariaLabelledby: 'titleID', ariaDescribedby: 'descriptionID', }}
// enable the Dialog plugin using a templatedialog: { template: { type: 'confirm', title: 'Confirm', description: 'Do you want change the value?', buttons: [ { text: 'Ok', type: 'primary', callback: () => { console.log('Ok'); } }, ], },}disableVisualSelection
options.disableVisualSelection : boolean | string | Array<string>
The disableVisualSelection option configures how
selection is shown.
You can set the disableVisualSelection option to one of the following:
| Setting | Description |
|---|---|
false (default) | - Show single-cell selection - Show range selection - Show header selection |
true | - Don’t show single-cell selection - Don’t show range selection - Don’t show header selection |
'current' | - Don’t show single-cell selection - Show range selection - Show header selection |
'area' | - Show single-cell selection - Don’t show range selection - Show header selection |
'header' | - Show single-cell selection - Show range selection - Don’t show header selection |
| An array | A combination of 'current', 'area', and/or 'header' |
This option can only be set at the grid level.
It has no effect when set in the columns, cells, or cell options.
Read more:
Default: false
Category: Core
Example
// don't show single-cell selection// don't show range selection// don't show header selectiondisableVisualSelection: true,
// don't show single-cell selection// show range selection// show header selectiondisableVisualSelection: 'current',
// don't show single-cell selection// don't show range selection// show header selectiondisableVisualSelection: ['current', 'area'],dragToScroll
options.dragToScroll : boolean
The dragToScroll option configures the DragToScroll plugin.
You can set the dragToScroll option to one of the following:
| Setting | Description |
|---|---|
true (default) | When selection reaches the edge of the grid’s viewport, scroll the viewport |
false | Don’t scroll the viewport |
Read more:
Default: true
Category: DragToScroll
Example
// when selection reaches the edge of the grid's viewport, scroll the viewportdragToScroll: true,dropdownMenu
options.dropdownMenu : boolean | object | Array<string>
The dropdownMenu option configures the DropdownMenu plugin.
You can set the dropdownMenu option to one of the following:
| Setting | Description |
|---|---|
false | Disable the DropdownMenu plugin |
true | - Enable the DropdownMenu plugin- Use the default context menu options |
| An array | - Enable the DropdownMenu plugin- Modify individual context menu options |
| An object | - Enable the DropdownMenu plugin- Apply a custom dropdown menu configuration |
This option can only be set at the grid level. It is not possible to show or hide the dropdown menu icon for individual columns using this option.
Read more:
Default: undefined
Category: DropdownMenu
Example
// enable the `DropdownMenu` plugin// use the default context menu optionsdropdownMenu: true,
// enable the `DropdownMenu` plugin// and modify individual context menu optionsdropdownMenu: ['---------', 'undo', 'redo'],
// enable the `DropdownMenu` plugin// and apply a custom dropdown menu configurationdropdownMenu: { items: { 'option1': { name: 'Option 1' }, 'option2': { name: 'Option 2', submenu: { items: [ { key: 'option2:suboption1', name: 'Suboption 1', callback(key, options) { ... } }, ... ] } } }},editor
options.editor : string | function | boolean
The editor option sets a cell editor for a cell.
You can set the editor option to one of the following cell editor aliases:
| Alias | Cell editor function |
|---|---|
| A custom alias | Your custom cell editor function |
'autocomplete' | AutocompleteEditor |
'base' | BaseEditor |
'checkbox' | CheckboxEditor |
'date' | DateEditor |
'intl-date' | IntlDateEditor |
'dropdown' | DropdownEditor |
'handsontable' | HandsontableEditor |
'numeric' | NumericEditor |
'password' | PasswordEditor |
'select' | SelectEditor |
'text' | TextEditor |
'time' | TimeEditor |
'intl-time' | IntlTimeEditor |
To disable editing cells through cell editors,
set the editor option to false.
You’ll still be able to change cells’ content through Handsontable’s API
or through plugins (e.g. CopyPaste), though.
To set the editor, renderer, and validator
options all at once, use the type option.
Read more:
Default: undefined
Category: Core
Example
// use the `numeric` editor for each cell of the entire grideditor: 'numeric',
// apply the `editor` option to individual columnscolumns: [ { // use the `autocomplete` editor for each cell of this column editor: 'autocomplete' }, { // disable editing cells through cell editors for each cell of this column editor: false }]emptyDataState
options.emptyDataState : boolean | object
The emptyDataState option configures the EmptyDataState plugin.
You can set the emptyDataState option to one of the following:
| Setting | Description |
|---|---|
false | Disable the EmptyDataState plugin |
true | Enable the EmptyDataState plugin |
| An object | Enable the EmptyDataState plugin with custom settings |
If you set the emptyDataState option to an object, you can configure the following settings:
| Property | Possible values | Description |
|---|---|---|
message | string | object | function | Message to display in the empty data state overlay. |
If you set the message option to an object, it have following properties:
| Property | Possible values | Description |
|---|---|---|
title | string | Title to display in the empty data state overlay. |
description | string | Description to display in the empty data state overlay. |
buttons | array | Buttons to display in the empty data state overlay. |
loading | boolean | When true, shows a loading spinner (used for server fetch state). |
If you set the message option to a function, the source argument can be "unknown", "filters", or "loading".
With [[Options#dataProvider]], the "loading" branch follows DataProvider fetch hooks (beforeDataProviderFetch,
afterDataProviderFetch, and related hooks) using the same rules as server-backed loading in the DataProvider plugin.
Internal refetches (for example after column sort or CRUD) set skipLoading on [[Hooks#beforeDataProviderFetch]] so the
EmptyDataState plugin can omit the loading overlay for those requests.
If you set the buttons option to an array, each item requires following properties:
| Property | Possible values | Description |
|---|---|---|
text | string | Text to display in the button. |
type | ’primary’ | ‘secondary’ | Type of the button. |
callback | function | Callback function to call when the button is clicked. |
Read more:
Default: false
Category: EmptyDataState
Since: 16.2.0
Example
// Enable empty data state plugin with default messagesemptyDataState: true,
// Enable empty data state plugin with custom messageemptyDataState: { message: 'No data available',},
// Enable empty data state plugin with custom message and buttons for any sourceemptyDataState: { message: { title: 'No data available', description: 'There’s nothing to display yet.', buttons: [{ text: 'Reset filters', type: 'secondary', callback: () => {} }], },},
// Enable empty data state plugin with custom message and buttons for specific sourceemptyDataState: { message: (source) => { switch (source) { case "filters": return { title: 'No data available', description: 'There’s nothing to display yet.', buttons: [{ text: 'Reset filters', type: 'secondary', callback: () => {} }], }; case "loading": return { title: 'Loading data', description: 'Please wait.', }; default: return { title: 'No data available', description: 'There’s nothing to display yet.', }; } },},enterBeginsEditing
options.enterBeginsEditing : boolean
The enterBeginsEditing option configures the action of the Enter key.
You can set the enterBeginsEditing option to one of the following:
| Setting | Description |
|---|---|
true (default) | - On pressing Enter once, enter the editing mode of the active cell - On pressing Enter twice, move to another cell, as configured by the enterMoves setting |
false | - On pressing Enter once, move to another cell, as configured by the enterMoves setting |
Read more:
Default: true
Category: Core
Example
// press Enter once to start editing// press Enter twice to move to another cellenterBeginsEditing: true,
// press Enter once to move to another cellenterBeginsEditing: false,enterCommits
options.enterCommits : boolean
The enterCommits option configures whether the Enter key closes the multiSelect editor.
Default: true
Category: Core
Since: 17.0.0
Example
columns: [{ type: 'multiselect', // press Enter to close the `multiSelect` editor and Space to select an option enterCommits: true,}, { type: 'multiselect', // press Enter to select an option enterCommits: false,}],],enterMoves
options.enterMoves : object | function
The enterMoves option configures the action of the Enter key.
If the enterBeginsEditing option is set to true,
the enterMoves setting applies to the second pressing of the Enter key.
If the enterBeginsEditing option is set to false,
the enterMoves setting applies to the first pressing of the Enter key.
You can set the enterMoves option to an object with the following properties
(or to a function that returns such an object):
| Property | Type | Description |
|---|---|---|
col | Number | - On pressing Enter, move selection col columns right- On pressing Shift+Enter, move selection col columns left |
row | Number | - On pressing Enter, move selection row rows down- On pressing Shift+Enter, move selection row rows up |
Read more:
Default: {col: 0, row: 1}
Category: Core
Example
// on pressing Enter, move selection 1 column right and 1 row down// on pressing Shift+Enter, move selection 1 column left and 1 row upenterMoves: {col: 1, row: 1},
// the same setting, as a function// `event` is a DOM Event object received on pressing Enter// you can use it to check whether the user pressed Enter or Shift+EnterenterMoves(event) { return {col: 1, row: 1};},exportFile
options.exportFile : object
The exportFile option configures the ExportFile plugin.
You can set the exportFile option to one of the following:
| Setting | Description |
|---|---|
undefined | Use the ExportFile plugin with the default configuration |
| An object | Enable the ExportFile plugin and modify the plugin options |
If you set the exportFile option to an object, you can configure the following options:
| Option | Type | Default | Description |
|---|---|---|---|
engines | Object | – | A map of format keys to their engine constructors. Pass { xlsx: ExcelJS } to enable XLSX export via ExcelJS. |
Read more:
Default: undefined
Category: ExportFile
Since: 17.1.0
Example
import ExcelJS from 'exceljs';
// enable XLSX exportexportFile: { engines: { xlsx: ExcelJS },},fillHandle
options.fillHandle : boolean | string | object
The fillHandle option configures the Autofill plugin.
You can set the fillHandle option to one the following:
| Setting | Description |
|---|---|
true | - Enable autofill in all directions - Add the fill handle |
false | Disable autofill |
'vertical' | - Enable vertical autofill - Add the fill handle |
'horizontal' | - Enable horizontal autofill - Add the fill handle |
| An object | - Enable autofill - Add the fill handle - Configure autofill options |
If you set the fillHandle option to an object, you can configure the following autofill options:
| Option | Possible settings | Description |
|---|---|---|
autoInsertRow | true (default) | false | true: When you reach the grid’s bottom, add new rowsfalse: When you reach the grid’s bottom, stop |
direction | 'vertical' | 'horizontal' | 'vertical': Enable vertical autofill'horizontal': Enable horizontal autofill |
Read more:
Default: true
Category: Core
Example
// enable autofill in all directions// with `autoInsertRow` enabledfillHandle: true,
// enable vertical autofill// with `autoInsertRow` enabledfillHandle: 'vertical',
// enable horizontal autofill// with `autoInsertRow` enabledfillHandle: 'horizontal',
// enable autofill in all directions// with `autoInsertRow` disabledfillHandle: { autoInsertRow: false,},
// enable vertical autofill// with `autoInsertRow` disabledfillHandle: { autoInsertRow: false, direction: 'vertical'},filter
options.filter : boolean
The filter option configures whether autocomplete cells’
lists are updated by the end user’s input.
You can set the filter option to one of the following:
| Setting | Description |
|---|---|
true (default) | When the end user types into the input area, only options matching the input are displayed |
false | When the end user types into the input area, all options are displayed (options matching the input are put in bold |
Read more:
Default: true
Category: Core
Example
columns: [{ // set the `type` of each cell in this column to `autocomplete` type: 'autocomplete', // set options available in every `autocomplete` cell of this column source: ['A', 'B', 'C'], // when the end user types in `A`, display only the A option // when the end user types in `B`, display only the B option // when the end user types in `C`, display only the C option filter: true}],filteringCaseSensitive
options.filteringCaseSensitive : boolean
The filteringCaseSensitive option configures whether autocomplete and multiSelect-typed cells’
search inputs are case-sensitive.
You can set the filteringCaseSensitive option to one of the following:
| Setting | Description |
|---|---|
false (default) | autocomplete cells’ input is not case-sensitive |
true | autocomplete cells’ input is case-sensitive |
Read more:
Default: false
Category: Core
Example
columns: [ { type: 'autocomplete', source: [ ... ], // match case while searching autocomplete options filteringCaseSensitive: true }, { type: 'multiselect', source: [ ... ], // match case while searching multiSelect options filteringCaseSensitive: true }],filters
options.filters : boolean
The filters option configures the Filters plugin.
You can set the filters option to one of the following:
| Setting | Description |
|---|---|
false | Disable the Filters plugin |
true | Enable the Filters plugin |
| An object | Enable the Filters plugin with custom settings |
If you set the filters option to an object, you can configure the following settings:
| Property | Possible values | Description |
|---|---|---|
searchMode | 'show' | 'apply' | Enable filtering only visible elements |
If filers is set to true, the searchMode option is set to 'show' by default.
Read more:
Default: undefined
Category: Filters
Example
// enable the `Filters` pluginfilters: true,filterSelectedItems
options.filterSelectedItems : boolean
The filterSelectedItems option configures whether the selected items are filtered out of the dropdown, when using the search input of the multiSelect editor.
Default: true
Category: Core
Example
// filter out the selected items from the dropdownfilterSelectedItems: true,
// keep the selected items in the dropdownfilterSelectedItems: false,
### fixedColumnsLeft
<button type="button" class="ask-about-api-btn" data-option="fixedColumnsLeft" data-plugin="Options" aria-label="Ask AI about fixedColumnsLeft">Ask AI</button>
<a href="https://github.com/handsontable/handsontable/blob/ee4829c9fe261b172939f298b26fad39f69427b0/handsontable/handsontable/src/dataMap/metaManager/metaSchema.js#L2885" target="_blank" rel="noopener noreferrer" class="source-code-link">Source code</a>
_options.fixedColumnsLeft : number_
`fixedColumnsLeft` is a legacy option.
If your grid's [layout direction](/docs/javascript-data-grid/layout-direction/) is LTR (default), `fixedColumnsLeft` acts like the [`fixedColumnsStart`](#fixedcolumnsstart) option.
If your grid's [layout direction](/docs/javascript-data-grid/layout-direction/) is RTL, using `fixedColumnsLeft` throws an error.
Use [`fixedColumnsStart`](#fixedcolumnsstart), which works in any layout direction.
Read more:- [`fixedColumnsStart`](#fixedcolumnsstart)
**Default**: <code>0</code>**Category**: [Core](/docs/javascript-data-grid/api/core/)**Example**```js// freeze the first 3 columns from the leftfixedColumnsLeft: 3,fixedColumnsStart
options.fixedColumnsStart : number
If your grid’s layout direction is LTR (default), the fixedColumnsStart option sets the number of frozen columns at the left-hand edge of the grid.
If your grid’s layout direction is RTL, the fixedColumnsStart option sets the number of frozen columns at the right-hand edge of the grid.
Read more:
Default: 0
Category: Core
Example
// when `layoutDirection` is set to `inherit` (default)// freeze the first 3 columns from the left or from the right// depending on your HTML document's `dir` attributelayoutDirection: 'inherit',fixedColumnsStart: 3,
// when `layoutDirection` is set to `rtl`// freeze the first 3 columns from the right// regardless of your HTML document's `dir` attributelayoutDirection: 'rtl',fixedColumnsStart: 3,
// when `layoutDirection` is set to `ltr`// freeze the first 3 columns from the left// regardless of your HTML document's `dir` attributelayoutDirection: 'ltr',fixedColumnsStart: 3,fixedRowsBottom
options.fixedRowsBottom : number
The fixedRowsBottom option sets the number of frozen rows
at the bottom of the grid.
Read more:
Default: 0
Category: Core
Example
// freeze the bottom 3 rowsfixedRowsBottom: 3,fixedRowsTop
options.fixedRowsTop : number
The fixedRowsTop option sets the number of frozen rows at the top of the grid.
Read more:
Default: 0
Category: Core
Example
// freeze the top 3 rowsfixedRowsTop: 3,formulas
options.formulas : object
The formulas option configures the Formulas plugin.
The Formulas plugin uses the HyperFormula calculation engine.
To install HyperFormula, read the following:
You can set the formulas option to an object with the following properties:
| Property | Possible values |
|---|---|
engine | HyperFormula |A HyperFormula instance | A HyperFormula configuration object |
sheetId | A number |
sheetName | A string |
Read more:
- Plugins:
Formulas - Formula calculation
- HyperFormula documentation: Client-side installation
- HyperFormula documentation: Configuration options
Default: undefined
Category: Formulas
Example
// either add the `HyperFormula` classformulas: { // set `engine` to `HyperFormula` engine: HyperFormula, sheetId: 1, sheetName: 'Sheet 1'}
// or, add a HyperFormula instance// initialized with the `'internal-use-in-handsontable'` license keyconst hyperformulaInstance = HyperFormula.buildEmpty({ licenseKey: 'internal-use-in-handsontable',});
formulas: { // set `engine` to a HyperFormula instance engine: hyperformulaInstance, sheetId: 1, sheetName: 'Sheet 1'}
// or, add a HyperFormula configuration objectformulas: { // set `engine` to a HyperFormula configuration object engine: { hyperformula: HyperFormula // or `engine: hyperformulaInstance` leapYear1900: false, // this option comes from HyperFormula // add more HyperFormula configuration options }, sheetId: 1, sheetName: 'Sheet 1'}
// use the same HyperFormula instance in multiple Handsontable instances
// a Handsontable instance `hot1`formulas: { engine: HyperFormula, sheetId: 1, sheetName: 'Sheet 1'}
// a Handsontable instance `hot2`formulas: { engine: hot1.getPlugin('formulas').engine, sheetId: 1, sheetName: 'Sheet 1'}fragmentSelection
options.fragmentSelection : boolean | string
The fragmentSelection option configures text selection settings.
You can set the fragmentSelection option to one of the following:
| Setting | Description |
|---|---|
false (default) | Disable text selection |
true | Enable text selection in multiple cells at a time |
'cell' | Enable text selection in one cell at a time |
Default: false
Category: Core
Example
// enable text selection in multiple cells at a timefragmentSelection: true,
// enable text selection in one cell a timefragmentSelection: 'cell',headerClassName
options.headerClassName : string
The headerClassName option allows adding one or more class names to the column headers’ inner div element.
It can be used to align the labels in the column headers to left, center or right by setting this option to
htLeft, htCenter, or htRight respectively.
Default: undefined
Category: Core
Since: 14.5.0
Example
// Adding class names to all column headersheaderClassName: 'htRight my-class',
columns: [ { // Adding class names to the column header of a single column headerClassName: 'htRight my-class', }]height
options.height : number | ‘auto’ | string | function
The height option configures the height of your grid.
You can set the height option to one of the following:
| Setting | Example |
|---|---|
| A number of pixels | height: 500 |
| A string with a CSS unit | height: '75vw' |
'auto' | height: 'auto' |
| A function that returns a valid number or string | height() { return 500; } |
How 'auto' differs from leaving height unset
When you set height: 'auto', Handsontable writes height: auto; overflow: clip;
as inline styles on the root element. The grid then grows to match its content height.
No internal vertical scrollbar is created, so the page itself scrolls when the grid
exceeds the viewport.
When you leave height unset, Handsontable does not touch the root element’s inline
styles. Sizing is governed by your CSS, and the nearest ancestor with overflow: auto
or overflow: hidden becomes the scroll parent. If no such ancestor exists, the window
scrolls. See the Grid size guide for
details.
Read more:
Default: undefined
Category: Core
Example
// set the grid's height to 500pxheight: 500,
// set the grid's height to 75vhheight: '75vh',
// let the grid grow to fit all its rows (no internal vertical scroll)height: 'auto',
// set the grid's height to 500px, using a functionheight() { return 500;},hiddenColumns
options.hiddenColumns : boolean | object
The hiddenColumns option configures the HiddenColumns plugin.
You can set the hiddenColumns option to one of the following:
| Setting | Description |
|---|---|
false | Disable the HiddenColumns plugin |
true | Enable the HiddenColumns plugin with the default plugin options |
| An object | - Enable the HiddenColumns plugin- Modify the plugin options |
If you set the hiddenColumns to an object, you can set the following HiddenColumns plugin options:
| Property | Possible values | Description |
|---|---|---|
columns | An array of indexes | An array of indexes of columns that are hidden at initialization |
copyPasteEnabled | true | false | true: when copying or pasting data, take hidden columns into accountfalse: when copying or pasting data, don’t take hidden columns into account |
indicators | true | false | true: display UI markers to indicate the presence of hidden columnsfalse: display UI markers |
Read more:
Default: undefined
Category: HiddenColumns
Example
// enable the `HiddenColumns` pluginhiddenColumns: true,
// enable `HiddenColumns` plugin, and modify the plugin optionshiddenColumns: { // set columns that are hidden by default columns: [5, 10, 15], // when copying or pasting data, take hidden columns into account copyPasteEnabled: true, // show where hidden columns are indicators: true}hiddenRows
options.hiddenRows : boolean | object
The hiddenRows option configures the HiddenRows plugin.
You can set the hiddenRows option to one of the following:
| Setting | Description |
|---|---|
false | Disable the HiddenRows plugin |
true | Enable the HiddenRows plugin with the default plugin options |
| An object | - Enable the HiddenRows plugin- Modify the plugin options |
If you set the hiddenRows to an object, you can set the following HiddenRows plugin options:
| Property | Possible values | Description |
|---|---|---|
rows | An array of indexes | An array of indexes of rows that are hidden at initialization |
copyPasteEnabled | true | false | true: when copying or pasting data, take hidden rows into accountfalse: when copying or pasting data, don’t take hidden rows into account |
indicators | true | false | true: display UI markers to indicate the presence of hidden rowsfalse: display UI markers |
Read more:
Default: undefined
Category: HiddenRows
Example
// enable the `HiddenRows` pluginhiddenRows: true,
// enable `HiddenRows` plugin, and modify the plugin optionshiddenRows: { // set rows that are hidden by default rows: [5, 10, 15], // when copying or pasting data, take hidden rows into account copyPasteEnabled: true, // show where hidden rows are indicators: true}imeFastEdit
options.imeFastEdit : boolean
The imeFastEdit option allows using the “fast edit” feature for the IME users. It’s disabled by default
because of its incompatibility with some of the accessibility features.
Enabling this option can make a negative impact on how some screen readers handle reading the table cells.
Category: Core
Since: 14.0.0
initialState
options.initialState : object | undefined
The initialState option configures the grid’s initial state.
This object accepts any grid configuration option. In case of conflicts between
initialState and table settings, the table settings take precedence.
Note: The initialState option is ignored when passed to the
updateSettings() method.
Default: undefined
Category: Core
Since: 16.1.0
Example
initialState: { // configure initial column order manualColumnMove: [1, 0],},injectCoreCss
options.injectCoreCss : boolean
The injectCoreCss option controls whether Handsontable injects its core CSS into the document.
You can set the injectCoreCss option to one of the following:
| Setting | Description |
|---|---|
true (default) | Inject core styles into the document head |
false | Do not inject core styles (use when you load CSS yourself, e.g. import 'handsontable/styles/handsontable.css') |
Read more:
Default: true
Category: Core
Since: 17.0.0
Example
// inject core CSS (default)injectCoreCss: true,
// skip injection when you load Handsontable CSS yourselfinjectCoreCss: false,invalidCellClassName
options.invalidCellClassName : string
The invalidCellClassName option lets you add a CSS class name to cells
that were marked as invalid by the cell validator.
Read more:
- Cell validator
currentRowClassNamecurrentHeaderClassNameactiveHeaderClassNamecurrentColClassNamereadOnlyCellClassNamecommentedCellClassNamenoWordWrapClassNameTableClassNameclassName
Default: “htInvalid”
Category: Core
Example
// add a `highlight-error` CSS class name// to every `invalid` cell`invalidCellClassName: 'highlight-error',label
options.label : object
The label option configures checkbox cells` labels.
You can set the label option to an object with the following properties:
| Property | Possible values | Description |
|---|---|---|
position | 'after' (default) | 'before' | 'after': place the label to the right of the checkbox'before': place the label to the left of the checkbox |
value | A string | A function | The label’s text |
separated | false (default) | true | false: don’t separate the label from the checkboxtrue: separate the label from the checkbox |
property | A string | - A data object property name that’s used as the label’s text - Works only when the data option is set to an array of objects |
Read more:
Default: undefined
Category: Core
Example
columns: [{ type: 'checkbox', // add 'My label:' after the checkbox label: { position: 'before', value: 'My label: ', separated: true }}],language
options.language : string
The language option configures Handsontable’s language settings.
This option controls the language used for all built-in UI strings, including context menu labels,
column sorting labels, validation messages, and other user-visible text. It does not affect the locale
used for number or date formatting - use the locale option for that.
This option can only be set at the grid level.
It has no effect when set in the columns, cells, or cell options.
You can set the language option to one of the following:
| Setting | Description |
|---|---|
'en-US' (default) | English - United States |
'ar-AR' | Arabic - Global To properly render this language, set the layout direction to RTL. |
'cs-CZ' | Czech - Czech Republic |
'de-CH' | German - Switzerland |
'de-DE' | German - Germany |
'es-MX' | Spanish - Mexico |
'fa-IR' | Persian - Iran |
'fr-FR' | French - France |
'hr-HR' | Croatian - Croatia |
'it-IT' | Italian - Italy |
'ja-JP' | Japanese - Japan |
'ko-KR' | Korean - Korea |
'lv-LV' | Latvian - Latvia |
'nb-NO' | Norwegian (Bokmål) - Norway |
'nl-NL' | Dutch - Netherlands |
'pl-PL' | Polish - Poland |
'pt-BR' | Portuguese - Brazil |
'ru-RU' | Russian - Russia |
'sr-SP' | Serbian (Latin) - Serbia |
'zh-CN' | Chinese - China |
'zh-TW' | Chinese - Taiwan |
Read more:
Default: “en-US”
Category: Core
Example
// set Handsontable's language to Polishlanguage: 'pl-PL',layoutDirection
options.layoutDirection : string
The layoutDirection option configures whether Handsontable renders from the left to the right, or from the right to the left.
You can set the layout direction only at Handsontable’s initialization. Any change of the layoutDirection option after the initialization (e.g. using the updateSettings() method) is ignored.
You can set the layoutDirection option only for the entire grid.
You can’t set it for individual columns, rows, or cells.
You can set the layoutDirection option to one of the following strings:
| Setting | Description |
|---|---|
inherit (default) | Set Handsontable’s layout direction automatically, based on the value of your HTML document’s dir attribute |
rtl | Render Handsontable from the right to the left, even when your HTML document’s dir attribute is set to ltr |
ltr | Render Handsontable from the left to the right, even when your HTML document’s dir attribute is set to rtl |
Read more:
Default: “inherit”
Category: Core
Example
// inherit Handsontable's layout direction// from the value of your HTML document's `dir` attributelayoutDirection: 'inherit',
// render Handsontable from the right to the left// regardless of your HTML document's `dir`layoutDirection: 'rtl',
// render Handsontable from the left to the right// regardless of your HTML document's `dir`layoutDirection: 'ltr',licenseKey
options.licenseKey : string
The licenseKey option sets your Handsontable license key.
You can set the licenseKey option to one of the following:
| Setting | Description |
|---|---|
| A string with your commercial license key | For commercial use |
'non-commercial-and-evaluation' | For non-commercial use |
Read more:
Default: undefined
Category: Core
Example
// for commercial uselicenseKey: 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx', // your commercial license key
// for non-commercial uselicenseKey: 'non-commercial-and-evaluation',loading
options.loading : boolean | object
The loading option configures the Loading plugin.
Loading plugin, automatically loads Dialog plugin.
You can set the loading option to one of the following:
| Setting | Description |
|---|---|
false | Disable the Loading plugin |
true | Enable the Loading plugin with default configuration |
| An object | - Enable the Loading plugin- Apply custom configuration |
If you set the loading option to an object, you can configure the following loading options:
| Option | Possible settings | Description |
|---|---|---|
icon | A string | Custom loading icon to display (default: <svg />) |
title | A string | Custom loading title to display (default: 'Loading...') |
description | A string | Custom loading description to display (default: '') |
Read more:
Default: false
Category: Loading
Since: 16.1.0
Example
// enable the `Loading` plugin with default configurationloading: true,
// enable the `Loading` plugin with custom configurationloading: { icon: 'A custom loading icon in SVG format', title: 'Custom loading title', description: 'Custom loading description',}locale
options.locale : string
The locale option configures Handsontable’s locale settings.
You can set the locale option to any valid and canonicalized Unicode BCP 47 locale tag,
both for the entire grid,
and for individual columns.
Read more:
Default: “en-US”
Category: Core
Example
// set the entire grid's locale to Polishlocale: 'pl-PL',
// set individual columns' localescolumns: [ { // set the first column's locale to Polish locale: 'pl-PL', }, { // set the second column's locale to German locale: 'de-DE', },],manualColumnFreeze
options.manualColumnFreeze : boolean
The manualColumnFreeze option configures the ManualColumnFreeze plugin.
You can set the manualColumnFreeze option to one of the following:
| Setting | Description |
|---|---|
true | Enable the ManualColumnFreeze plugin |
false | Disable the ManualColumnFreeze plugin |
Read more:
Default: undefined
Category: ManualColumnFreeze
Example
// enable the `ManualColumnFreeze` pluginmanualColumnFreeze: true,manualColumnMove
options.manualColumnMove : boolean | Array<number>
The manualColumnMove option configures the ManualColumnMove plugin.
You can set the manualColumnMove option to one of the following:
| Setting | Description |
|---|---|
true | Enable the ManualColumnMove plugin |
false | Disable the ManualColumnMove plugin |
| An array | - Enable the ManualColumnMove plugin- Move individual columns at initialization |
Read more:
Default: undefined
Category: ManualColumnMove
Example
// enable the `ManualColumnMove` pluginmanualColumnMove: true,
// enable the `ManualColumnMove` plugin// at initialization, move column 0 to 1// at initialization, move column 1 to 4// at initialization, move column 2 to 6manualColumnMove: [1, 4, 6],manualColumnResize
options.manualColumnResize : boolean | Array<number>
The manualColumnResize option configures the ManualColumnResize plugin.
You can set the manualColumnResize option to one of the following:
| Setting | Description |
|---|---|
true | Enable the ManualColumnResize plugin |
false | Disable the ManualColumnResize plugin |
| An array | - Enable the ManualColumnResize plugin- Set initial widths of individual columns |
Read more:
Default: undefined
Category: ManualColumnResize
Example
// enable the `manualColumnResize` pluginmanualColumnResize: true,
// enable the `manualColumnResize` plugin// set the initial width of column 0 to 40 pixels// set the initial width of column 1 to 50 pixels// set the initial width of column 2 to 60 pixelsmanualColumnResize: [40, 50, 60],manualRowMove
options.manualRowMove : boolean | Array<number>
The manualRowMove option configures the ManualRowMove plugin.
You can set the manualRowMove option to one of the following:
| Setting | Description |
|---|---|
true | Enable the ManualRowMove plugin |
false | Disable the ManualRowMove plugin |
| An array | - Enable the ManualRowMove plugin- Move individual rows at initialization |
Read more:
Default: undefined
Category: ManualRowMove
Example
// enable the `ManualRowMove` pluginmanualRowMove: true,
// enable the `ManualRowMove` plugin// at initialization, move row 1 to 0// at initialization, move row 4 to 1// at initialization, move row 6 to 2manualRowMove: [1, 4, 6],manualRowResize
options.manualRowResize : boolean | Array<number>
The manualRowResize option configures the ManualRowResize plugin.
You can set the manualRowResize option to one of the following:
| Setting | Description |
|---|---|
true | Enable the ManualRowResize plugin |
false | Disable the ManualRowResize plugin |
| An array | - Enable the ManualRowResize plugin- Set initial heights of individual rows |
Read more:
Default: undefined
Category: ManualRowResize
Example
// enable the `ManualRowResize` pluginmanualRowResize: true,
// enable the `ManualRowResize` plugin// set the initial height of row 0 to 40 pixels// set the initial height of row 1 to 50 pixels// set the initial height of row 2 to 60 pixelsmanualRowResize: [40, 50, 60],maxCols
options.maxCols : number
The maxCols option sets a maximum number of columns.
The maxCols option is used:
- At initialization: if the
maxColsvalue is lower than the initial number of columns, Handsontable trims columns from the right. - At runtime: for example, when inserting columns.
Default: Infinity
Category: Core
Example
// set the maximum number of columns to 300maxCols: 300,maxRows
options.maxRows : number
The maxRows option sets a maximum number of rows.
The maxRows option is used:
- At initialization: if the
maxRowsvalue is lower than the initial number of rows, Handsontable trims rows from the bottom. - At runtime: for example, when inserting rows.
Default: Infinity
Category: Core
Example
// set the maximum number of rows to 300maxRows: 300,maxSelections
options.maxSelections : number
The maxSelections option sets a maximum number of selections for the multiSelect-typed cells.
Default: undefined
Category: Core
Since: 17.0.0
Example
columns: [{ // set the `type` of each cell in this column to `multiSelect` type: 'multiselect', // set the maximum number of selections to 3 maxSelections: 3,}],mergeCells
options.mergeCells : boolean | Array<object>
The mergeCells option configures the MergeCells plugin.
You can set the mergeCells option to one of the following:
| Setting | Description |
|---|---|
true | Enable the MergeCells plugin |
false | Disable the MergeCells plugin |
| An array of objects | - Enable the MergeCells plugin- Merge specific cells at initialization |
| { virtualized: true } | Enable the MergeCells plugin with enabled virtualization mode |
To merge specific cells at Handsontable’s initialization,
set the mergeCells option to an array of objects, with the following properties:
| Property | Description |
|---|---|
row | The row index of the merged section’s beginning |
col | The column index of the merged section’s beginning |
rowspan | The width (as a number of rows) of the merged section |
colspan | The height (as a number of columns ) of the merged section |
This option can only be set at the grid level.
It has no effect when set in the columns, cells, or cell options.
Read more:
Default: false
Category: MergeCells
Example
// enable the `MergeCells` pluginmergeCells: true,
// enable the `MergeCells` plugin// and merge specific cells at initializationmergeCells: [ // merge cells from cell (1,1) to cell (3,3) {row: 1, col: 1, rowspan: 3, colspan: 3}, // merge cells from cell (3,4) to cell (2,2) {row: 3, col: 4, rowspan: 2, colspan: 2}, // merge cells from cell (5,6) to cell (3,3) {row: 5, col: 6, rowspan: 3, colspan: 3}],
// enable the `MergeCells` plugin with enabled virtualization mode// and merge specific cells at initializationmergeCells: { virtualized: true, cells: [ // merge cells from cell (1,1) to cell (3,3) {row: 1, col: 1, rowspan: 3, colspan: 3}, // merge cells from cell (3,4) to cell (2,2) {row: 3, col: 4, rowspan: 2, colspan: 2}, // merge cells from cell (5,6) to cell (3,3) {row: 5, col: 6, rowspan: 3, colspan: 3} ],},minCols
options.minCols : number
The minCols option sets a minimum number of columns.
The minCols option is used:
- At initialization: if the
minColsvalue is higher than the initial number of columns, Handsontable adds empty columns to the right. - At runtime: for example, when removing columns.
The minCols option works only when your data is an array of arrays.
When your data is an array of objects,
you can only have as many columns as defined in:
- The first data row
- The
dataSchemaoption - The
columnsoption
Default: 0
Category: Core
Example
// set the minimum number of columns to 10minCols: 10,minRowHeights
options.minRowHeights : number | Array<number> | string | Array<string> | Array<undefined> | function
Alias for the rowHeights option.
See the rowHeights option description for more information.
Default: undefined
Category: Core
Since: 16.2.0
Example
// set every row's minimum height to 100pxminRowHeights: 100,
// set every row's minimum height to 100pxminRowHeights: '100px',
// set the first (by visual index) row's minimum height to 100// set the second (by visual index) row's minimum height to 120// set any other row's minimum height to the default height valueminRowHeights: [100, 120],
// set each row's minimum height individually, using a functionminRowHeights(visualRowIndex) { return visualRowIndex * 10;},minRows
options.minRows : number
The minRows option sets a minimum number of rows.
The minRows option is used:
- At initialization: if the
minRowsvalue is higher than the initial number of rows, Handsontable adds empty rows at the bottom. - At runtime: for example, when removing rows.
Default: 0
Category: Core
Example
// set the minimum number of rows to 10minRows: 10,minSpareCols
options.minSpareCols : number
The minSpareCols option sets a minimum number of empty columns
at the grid’s right-hand end.
If there already are other empty columns at the grid’s right-hand end,
they are counted into the minSpareCols value.
The total number of columns can’t exceed the maxCols value.
The minSpareCols option works only when your data is an array of arrays.
When your data is an array of objects,
you can only have as many columns as defined in:
- The first data row
- The
dataSchemaoption - The
columnsoption
Default: 0
Category: Core
Example
// at Handsontable's initialization, add at least 3 empty columns on the rightminSpareCols: 3,minSpareRows
options.minSpareRows : number
The minSpareRows option sets a minimum number of empty rows
at the bottom of the grid.
If there already are other empty rows at the bottom,
they are counted into the minSpareRows value.
The total number of rows can’t exceed the maxRows value.
Default: 0
Category: Core
Example
// at Handsontable's initialization, add at least 3 empty rows at the bottomminSpareRows: 3,multiColumnSorting
options.multiColumnSorting : boolean | object
The multiColumnSorting option configures the MultiColumnSorting plugin.
You can set the multiColumnSorting option to one of the following:
| Setting | Description |
|---|---|
true | Enable the MultiColumnSorting plugin with the default configuration |
false | Disable the MultiColumnSorting plugin |
| An object | - Enable the MultiColumnSorting plugin- Modify the MultiColumnSorting plugin options |
If you set the multiColumnSorting option to an object,
you can set the following MultiColumnSorting plugin options:
| Option | Possible settings |
|---|---|
indicator | true: Display the arrow icon in the column header, to indicate a sortable columnfalse: Don’t display the arrow icon in the column header |
headerAction | true: Enable clicking on the column header to sort the columnfalse: Disable clicking on the column header to sort the column |
sortEmptyCells | true: Sort empty cells as wellfalse: Place empty cells at the end |
compareFunctionFactory | A custom compare function |
If you set the multiColumnSorting option to an object,
you can also sort individual columns at Handsontable’s initialization.
In the multiColumnSorting object, add an object named initialConfig,
with the following properties:
| Option | Possible settings | Description |
|---|---|---|
column | A number | The index of the column that you want to sort at initialization |
sortOrder | 'asc' | 'desc' | The sorting order:'asc': ascending'desc': descending |
Read more:
Default: undefined
Category: MultiColumnSorting
Example
// enable the `MultiColumnSorting` pluginmultiColumnSorting: true
// enable the `MultiColumnSorting` plugin with custom configurationmultiColumnSorting: { // sort empty cells as well sortEmptyCells: true, // display the arrow icon in the column header indicator: true, // disable clicking on the column header to sort the column headerAction: false, // add a custom compare function compareFunctionFactory(sortOrder, columnMeta) { return function(value, nextValue) { // some value comparisons which will return -1, 0 or 1... } }}
// enable the `MultiColumnSorting` plugin with a multi-column initial sort order:// sort column 1 ascending first, then column 2 descendingmultiColumnSorting: { initialConfig: [ { column: 1, sortOrder: 'asc' }, { column: 2, sortOrder: 'desc' } ]}navigableHeaders
options.navigableHeaders : boolean
When set to true, the navigableHeaders option lets you navigate row headers and column headers, using the arrow keys or the Tab key (if the tabNavigation option is set to true).
Default: false
Category: Core
Since: 14.0.0
Example
// you can navigate row and column headers with the keyboardnavigableHeaders: true,
// default behavior: you can't navigate row and column headers with the keyboardnavigableHeaders: false,nestedHeaders
options.nestedHeaders : boolean | Array<Array>
The nestedHeaders option configures the NestedHeaders plugin.
You can set the nestedHeaders option to one of the following:
| Setting | Description |
|---|---|
false (default) | Disable the NestedHeaders plugin |
true | - Enable the NestedHeaders plugin- Don’t configure any nested headers |
| Array of arrays | - Enable the NestedHeaders plugin- Configure headers that are nested on Handsontable’s initialization |
If you set the nestedHeaders option to an array of arrays, each array configures one set of nested headers.
Each array element configures one header, and can be one of the following:
| Array element | Description |
|---|---|
| A string | The header’s label |
| An object | Properties:label (string): the header’s labelcolspan (integer): number of data columns the header spansrowspan (integer): number of header rows the header spansheaderClassName (string): optional space-separated CSS class names |
Read more:
Default: undefined
Category: NestedHeaders
Example
nestedHeaders: [ ['A', {label: 'B', colspan: 8}, 'C'], ['D', {label: 'E', colspan: 4}, {label: 'F', colspan: 4}, 'G'], ['H', 'I', 'J', 'K', 'L', 'M', 'N', 'R', 'S', 'T']],nestedRows
options.nestedRows : boolean
The nestedRows option configures the NestedRows plugin.
You can set the nestedRows option to one of the following:
| Setting | Description |
|---|---|
false (default) | Disable the NestedRows plugin |
true | Enable the NestedRows plugin |
Read more:
Default: false
Category: NestedRows
Example
// enable the `NestedRows` pluginnestedRows: true,notification
options.notification : boolean | object
The notification option configures the Notification plugin.
You can set the notification option to one of the following:
| Setting | Description |
|---|---|
false | Disable the Notification plugin |
true | Enable the plugin with default options |
| An object | Enable the plugin and set stackLimit and animation |
notification: Additional options
| Option | Type | Default | Description |
|---|---|---|---|
stackLimit | number | 10 | Maximum visible toasts per corner. Extra requests are queued. |
animation | boolean | true | Fade and slide animation when toasts appear. |
Read more:
Default: false
Category: Notification
Since: 17.1.0
Example
notification: true,noWordWrapClassName
options.noWordWrapClassName : string
The noWordWrapClassName option lets you add a CSS class name
to each cell that has the wordWrap option set to false.
Read more:
wordWrapcurrentRowClassNamecurrentColClassNamecurrentHeaderClassNameinvalidCellClassNamereadOnlyCellClassNamecommentedCellClassNamenoWordWrapClassNameTableClassNameclassName
Default: “htNoWrap”
Category: Core
Example
// add an `is-noWrapCell` CSS class name// to each cell that doesn't wrap contentnoWordWrapClassName: 'is-noWrapCell',numericFormat
options.numericFormat : object
Configures the number format for numeric
cells, including currency, units, precision, and other display options.
Since v17.0.0, this option accepts all properties of the
Intl.NumberFormatOptions
object. The locale is controlled separately via the locale option.
Style options:
| Property | Possible values | Description |
|---|---|---|
style | 'decimal' (default), 'currency', 'percent', 'unit' | The formatting style to use |
currency | ISO 4217 currency codes (e.g., 'USD', 'EUR', 'PLN') | Required when style is 'currency' |
currencyDisplay | 'symbol' (default), 'narrowSymbol', 'code', 'name' | How to display the currency |
currencySign | 'standard' (default), 'accounting' | Use parentheses for negative values in accounting format |
unit | Unit identifiers (e.g., 'kilometer', 'liter') | Required when style is 'unit' |
unitDisplay | 'short' (default), 'narrow', 'long' | How to display the unit |
Notation options:
| Property | Possible values | Description |
|---|---|---|
notation | 'standard' (default), 'scientific', 'engineering', 'compact' | The formatting notation |
compactDisplay | 'short' (default), 'long' | Display style for compact notation (e.g., 1.5M vs 1.5 million) |
Sign and grouping options:
| Property | Possible values | Description |
|---|---|---|
signDisplay | 'auto' (default), 'never', 'always', 'exceptZero', 'negative' | When to display the sign |
useGrouping | true, false (default), 'always', 'auto', 'min2' | Whether to use grouping separators (e.g., 1,000) |
Digit options:
| Property | Possible values | Description |
|---|---|---|
minimumIntegerDigits | 1 to 21 | Minimum number of integer digits (pads with zeros) |
minimumFractionDigits | 0 to 100 | Minimum number of fraction digits |
maximumFractionDigits | 0 to 100 | Maximum number of fraction digits |
minimumSignificantDigits | 1 to 21 | Minimum number of significant digits |
maximumSignificantDigits | 1 to 21 | Maximum number of significant digits |
Rounding options:
| Property | Possible values | Description |
|---|---|---|
roundingMode | 'halfExpand' (default), 'ceil', 'floor', 'expand', 'trunc', 'halfCeil', 'halfFloor', 'halfTrunc', 'halfEven' | Rounding algorithm |
roundingPriority | 'auto' (default), 'morePrecision', 'lessPrecision' | Priority between fraction and significant digits |
roundingIncrement | 1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000 | Increment for rounding (e.g., nickel rounding) |
trailingZeroDisplay | 'auto' (default), 'stripIfInteger' | Whether to strip trailing zeros for integers |
Locale options:
| Property | Possible values | Description |
|---|---|---|
localeMatcher | 'best fit' (default), 'lookup' | Locale matching algorithm |
numberingSystem | 'latn', 'arab', 'hans', 'deva', 'thai', etc. | Numbering system to use |
For complete reference, see MDN: Intl.NumberFormat.
This option affects only the displayed output in the cell renderer. It has no effect on the numeric cell editor. In the source data, numeric values are stored as JavaScript numbers.
Read more:
Deprecated options:
The pattern and culture properties (numbro.js-based formatting) are deprecated and will be
removed in the next major release. Migrate to the Intl.NumberFormat API shown above.
| Deprecated property | Possible values | Replacement |
|---|---|---|
pattern | All numbro.js number formats | Use Intl.NumberFormat options (see tables above) |
culture | All numbro.js currency formats | Use the locale option |
Migration example:
// Before (deprecated)numericFormat: { pattern: '0,0.00 $', culture: 'en-US'}
// After (recommended)locale: 'en-US',numericFormat: { style: 'currency', currency: 'USD', minimumFractionDigits: 2}Default: undefined
Category: Core
Since: 0.35.0
Example
columns: [ { type: 'numeric', locale: 'en-US', numericFormat: { style: 'currency', currency: 'USD', } }],observeDOMVisibility
options.observeDOMVisibility : boolean
If the observeDOMVisibility option is set to true,
Handsontable rerenders every time it detects that the grid was made visible in the DOM.
Handsontable uses a MutationObserver to watch for CSS changes (such as display: none being removed)
on the container element and its ancestors. When visibility is restored after being hidden,
Handsontable automatically triggers a rerender to ensure correct layout and dimensions.
Set this option to false if you want to control rendering manually (e.g. by calling render() yourself).
Default: true
Category: Core
Example
// don't rerender the grid on visibility changesobserveDOMVisibility: false,outsideClickDeselects
options.outsideClickDeselects : boolean | function
The outsideClickDeselects option determines what happens to the current selection
when you click outside of the grid.
You can set the outsideClickDeselects option to one of the following:
| Setting | Description |
|---|---|
true (default) | On a mouse click outside of the grid, clear the current selection |
false | On a mouse click outside of the grid, keep the current selection |
| A function | A function that takes the click event target and returns a boolean |
Default: true
Category: Core
Example
// on a mouse click outside of the grid, clear the current selectionoutsideClickDeselects: true,
// on a mouse click outside of the grid, keep the current selectionoutsideClickDeselects: false,
// take the click event target and return `false`outsideClickDeselects(event) { return false;}
// take the click event target and return `true`outsideClickDeselects(event) { return false;}pagination
options.pagination : boolean
The pagination option configures the Pagination plugin.
You can set the pagination option to one of the following:
| Setting | Description |
|---|---|
false | Disable the Pagination plugin |
true | Enable the Pagination plugin |
pagination: Additional options
If you set the pagination option to an object, you can set the following Pagination plugin options:
| Option | Possible settings | Description |
|---|---|---|
pageSize | A number or auto (default: 10) | Sets the number of rows displayed per page. If 'auto' is set, the page size will be calculated to match all rows to the currently set table’s viewport height |
pageSizeList | An array (default: ['auto', 5, 10, 20, 50, 100]) | Defines the selectable values for page size in the UI |
initialPage | A number (default: 1) | Specifies which page to display on initial load |
showPageSize | Boolean (default: true) | Controls visibility of the “page size” section |
showCounter | Boolean (default: true) | Controls visibility of the “page counter” section (e.g., “1 - 10 of 50”); |
showNavigation | Boolean (default: true) | Controls visibility of the “page navigation” section |
uiContainer | An HTML element (default: null) | The container element where the pagination UI will be installed. If not provided, the pagination container will be injected below the root table element. |
Read more:
Default: undefined
Category: Pagination
Since: 16.1.0
Example
// enable the `Pagination` pluginpagination: true,parsePastedValue
options.parsePastedValue : boolean
The parsePastedValue option determines how pasted content is written to cells when the user pastes
from the clipboard into Handsontable (e.g. from another Handsontable instance or between cells in the same table).
It does not affect how other applications read or process the clipboard.
When set to false, pasted content is written as plain strings. Non-scalar values (e.g. objects) are coerced
to string, so an object becomes "[object Object]".
When set to true, pasted text is parsed so that JSON-like (or other supported) values are converted to
JavaScript values and written to the data source. This allows copying and pasting more sophisticated JavaScript
structures (e.g. objects, arrays) between cells and between Handsontable instances. Cells then store the resulting
object (e.g. { id: 1, value: 'A1' }). Schema validation is relaxed so object-based values can be pasted into
cells that would normally expect a scalar.
You can set the parsePastedValue option to one of the following:
| Setting | Description |
|---|---|
false (default) | Write pasted content as plain strings |
true | Parse pasted text and write JavaScript values |
Default: false
Category: CopyPaste
Since: 17.0.0
Example
// write pasted content as strings (objects become "[object Object]")parsePastedValue: false,Example
// parse pasted text so cells receive JavaScript objects when pasted content is object-likeparsePastedValue: true,placeholder
options.placeholder : string
The placeholder option lets you display placeholder text in every empty cell.
You can set the placeholder option to one of the following:
| Setting | Example | Description |
|---|---|---|
| A non-empty string | 'Empty cell' | Display Empty cell text in empty cells |
| A non-string value | 000 | Display 000 text in empty cells (non-string values get stringified) |
Read more:
Default: undefined
Category: Core
Example
// display 'Empty cell' text// in every empty cell of the entire gridplaceholder: 'Empty cell',
// orcolumns: [ { data: 'date', dateFormat: 'DD/MM/YYYY', // display 'Empty date cell' text // in every empty cell of the `date` column placeholder: 'Empty date cell' }],placeholderCellClassName
options.placeholderCellClassName : string
The placeholderCellClassName option lets you add a CSS class name to cells
that contain placeholder text.
Read more:
- Cell validator
placeholdercurrentRowClassNamecurrentHeaderClassNameactiveHeaderClassNamecurrentColClassNamereadOnlyCellClassNamecommentedCellClassNamenoWordWrapClassNameTableClassNameclassName
Default: “htPlaceholder”
Category: Core
Example
// add a `has-placeholder` CSS class name// to each cell that contains `placeholder` textplaceholderCellClassName: 'has-placeholder',preventOverflow
options.preventOverflow : string | boolean
The preventOverflow option configures preventing Handsontable
from overflowing outside of its parent element.
When enabled, Handsontable caps its own dimensions to match the parent container’s size in the specified direction,
preventing the grid from extending beyond the visible bounds of its parent.
This is useful when the parent element has overflow: hidden or a fixed size and you want the grid to fit within it.
You can set the preventOverflow option to one of the following:
| Setting | Description |
|---|---|
false (default) | Don’t prevent overflowing |
'horizontal' | Prevent horizontal overflowing |
'vertical' | Prevent vertical overflowing |
Default: false
Category: Core
Example
// prevent horizontal overflowingpreventOverflow: 'horizontal',readOnly
options.readOnly : boolean
The readOnly option determines whether a cell,
comment, column
or the entire grid is editable or not. You can configure it as follows:
| Setting | Description |
|---|---|
false (default) | Set as editable |
true | - Set as read-only - Add the readOnlyCellClassName CSS class name (by default: htDimmed) |
readOnly cells can’t be changed by the populateFromArray() method.
Read more:
Default: false
Category: Core
Example
// make the entire grid read-onlyconst configurationOptions = { columnSorting: true,};
// make the third column read-onlyconst configurationOptions = { columns: [ {}, {}, { readOnly: true, }, ],};
// make a specific cell read-onlyconst configurationOptions = { cell: [ { row: 0, col: 0, readOnly: true, },};readOnlyCellClassName
options.readOnlyCellClassName : string
The readOnlyCellClassName option lets you add a CSS class name to read-only cells.
Read more:
currentRowClassNamecurrentColClassNamecurrentHeaderClassNameactiveHeaderClassNameinvalidCellClassNameplaceholderCellClassNamecommentedCellClassNamenoWordWrapClassNamereadOnlyCellClassNameTableClassName
Default: “htDimmed”
Category: Core
Example
// add a `is-readOnly` CSS class name// to every read-only cellreadOnlyCellClassName: 'is-readOnly',renderAllColumns
options.renderAllColumns : boolean
The renderAllColumns option configures Handsontable’s column virtualization.
You can set the renderAllColumns option to one of the following:
| Setting | Description |
|---|---|
false (default) | Enable column virtualization, rendering only visible columns for better performance with many columns. |
true | Disable column virtualization (render all columns of the grid), rendering all columns in the dataset, and ensuring all columns are available regardless of horizontal scrolling. |
Setting renderAllColumns to true overwrites the viewportColumnRenderingOffset setting.
Read more:
Default: false
Category: Core
Since: 14.1.0
Example
// disable column virtualizationrenderAllColumns: true,renderAllRows
options.renderAllRows : boolean
The renderAllRows option controls Handsontable’s row virtualization.
You can configure it as follows:
| Setting | Description |
|---|---|
false (default) | Enable row virtualization, rendering only the visible rows for optimal performance with large datasets. |
true | Disable row virtualization (render all rows of the grid), rendering all rows in the dataset for consistent rendering and screen reader accessibility. |
Setting renderAllRows to true overwrites the viewportRowRenderingOffset setting.
Read more:
Default: false
Category: Core
Example
// disable row virtualizationrenderAllRows: true,renderer
options.renderer : string | function
The renderer option sets a cell renderer for a cell.
You can set the renderer option to one of the following:
- A custom renderer function
- One of the following cell renderer aliases:
| Alias | Cell renderer function |
|---|---|
| A custom alias | Your custom cell renderer function |
'autocomplete' | AutocompleteRenderer |
'base' | BaseRenderer |
'checkbox' | CheckboxRenderer |
'date' | DateRenderer |
'intl-date' | IntlDateRenderer |
'dropdown' | DropdownRenderer |
'html' | HtmlRenderer |
'numeric' | NumericRenderer |
'password' | PasswordRenderer |
'text' | TextRenderer |
'time' | TimeRenderer |
'intl-time' | IntlTimeRenderer |
To set the renderer, editor, and validator
options all at once, use the type option.
Read more:
Default: undefined
Category: Core
Example
// use the `numeric` renderer for each cell of the entire gridrenderer: `'numeric'`,
// add a custom renderer functionrenderer(hotInstance, td, row, column, prop, value, cellProperties) { // your custom renderer's logic ...}
// apply the `renderer` option to individual columnscolumns: [ { // use the `autocomplete` renderer for each cell of this column renderer: 'autocomplete' }, { // use the `myCustomRenderer` renderer for each cell of this column renderer: 'myCustomRenderer' }]rowHeaders
options.rowHeaders : boolean | Array<string> | function
The rowHeaders option configures your grid’s row headers.
You can set the rowHeaders option to one of the following:
| Setting | Description |
|---|---|
true | Enable the default row headers (‘1’, ‘2’, ‘3’, …) |
false | Disable row headers |
| An array | Define your own row headers (e.g. ['One', 'Two', 'Three', ...]) |
| A function | Define your own row headers, using a function |
Read more:
Default: undefined
Category: Core
Example
// enable the default row headersrowHeaders: true,
// set your own row headersrowHeaders: ['One', 'Two', 'Three'],
// set your own row headers, using a functionrowHeaders: function(visualRowIndex) { return `${visualRowIndex}: AB`;},rowHeaderWidth
options.rowHeaderWidth : number | Array<number>
The rowHeaderWidth option configures the width of row headers.
You can set the rowHeaderWidth option to one of the following:
| Setting | Description |
|---|---|
| A number | Set the same width for every row header |
| An array | Set different widths for individual row headers |
Default: undefined
Category: Core
Example
// set the same width for every row headerrowHeaderWidth: 25,
// set different widths for individual row headersrowHeaderWidth: [25, 30, 55],rowHeights
options.rowHeights : number | Array<number> | string | Array<string> | Array<undefined> | function
The rowHeights option sets rows’ heights, in pixels.
In the rendering process, the default row height is classic: 26px, main: 29px, horizon: 37px or whatever is defined in the used theme (based on the line height, vertical padding and cell borders).
You can change it to equal or greater than the default value, by setting the rowHeights option to one of the following:
| Setting | Description | Example |
|---|---|---|
| A number | Set the same height for every row | rowHeights: 100 |
| A string | Set the same height for every row | rowHeights: '100px' |
| An array | Set heights separately for each row | rowHeights: [100, 120, undefined] |
| A function | Set row heights dynamically, on each render | rowHeights(visualRowIndex) { return visualRowIndex * 10; } |
undefined | Used by the modifyRowHeight hook, to detect row height changes | rowHeights: undefined |
The rowHeights option also sets the minimum row height that can be set
via the ManualRowResize and AutoRowSize plugins (if they are enabled).
Read more:
Default: undefined
Category: Core
Example
// set every row's height to 100pxrowHeights: 100,
// set every row's height to 100pxrowHeights: '100px',
// set the first (by visual index) row's height to 100// set the second (by visual index) row's height to 120// set the third (by visual index) row's height to `undefined`// set any other row's height to the default height valuerowHeights: [100, 120, undefined],
// set each row's height individually, using a functionrowHeights(visualRowIndex) { return visualRowIndex * 10;},sanitizer
options.sanitizer : function
The sanitizer option configures the function used to sanitize HTML before it is written to the DOM.
Whenever Handsontable sets HTML (e.g. cell content, headers, context menu labels, dialog content,
paste from clipboard), it can pass the string through this function first. Sanitization is important
when content comes from users or external sources to prevent XSS (e.g. script injection, event handlers).
If no sanitizer is set, HTML is applied as-is. Set a sanitizer when you need to allow rich content
while stripping or neutralizing dangerous markup.
The function receives the raw HTML string and an optional second argument (source) indicating where
the content is used (e.g. 'innerHTML', 'CopyPaste.paste'), so you can apply different rules per source.
It must return a string that is safe to assign to innerHTML.
This option is only respected when set in the table settings. It does not work when defined per column
or per cell (e.g. in columns or cell meta).
Default: undefined
Category: Core
Since: 17.0.0
Example
// Allowlist-based sanitization based on the DOMPurify libraryimport DOMPurify from 'dompurify';
sanitizer: (content, source) { if (source === 'CopyPaste.paste') { return DOMPurify.sanitize(content, { ADD_TAGS: ['meta'], ADD_ATTR: ['content'], FORCE_BODY: true, }); }
return DOMPurify.sanitize(content);},Example
// Maximum safety: strip all tags and escape output (no rich HTML)sanitizer: (content, source) => { const tpl = document.createElement('template');
tpl.innerHTML = content;
const text = tpl.content.textContent ?? '';
return text .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, ''');},Example
// Trusted Types: wrap sanitization in a policy so the sink accepts the result.// Add the policy name to the CSP trusted-types directive (e.g. trusted-types default handsontable).const policy = window.trustedTypes?.createPolicy('handsontable', { createHTML: (input) => DOMPurify.sanitize(input),});
sanitizer: (content, source) => policy ? policy.createHTML(content) : DOMPurify.sanitize(content),search
options.search : boolean | object
The search option enables and configures the Search plugin.
| Setting | Description |
|---|---|
false (default) | Disable the Search plugin |
true | Enable the Search plugin with the default configuration |
| An object | Enable the Search plugin and apply a custom configuration |
When set to an object, the following properties are supported:
| Property | Type | Default | Description |
|---|---|---|---|
searchResultClass | string | 'htSearchResult' | CSS class name applied to every cell where isSearchResult === true. |
queryMethod | Function | Case-insensitive substring match | Tests whether the query string matches a cell value. Signature: (queryStr: string, value: string|number|null, cellProperties: object) => boolean. |
callback | Function | Sets isSearchResult on cell metadata | Called for every cell after each test. Signature: (instance: Handsontable, row: number, col: number, data: string|number|null, testResult: boolean) => void. |
Default queryMethod behavior: case-insensitive, locale-aware substring match using toLocaleLowerCase() with cellProperties.locale.
Default callback behavior: sets instance.getCellMeta(row, col).isSearchResult = testResult on every cell.
Per-cell overrides: queryMethod and callback can also be set on individual cells, columns, or rows
using the cascading configuration model. A cell-level search.queryMethod or search.callback takes
precedence over the plugin-level setting for that cell. searchResultClass does not support per-cell overrides.
Read more:
Default: false
Category: Search
Example
// Enable with the default configurationsearch: true,
// Enable with a custom configurationsearch: { // Apply a custom CSS class to matching cells instead of 'htSearchResult' searchResultClass: 'customClass', // Replace the built-in substring match with exact matching queryMethod(queryStr, value, cellProperties) { if (!queryStr || queryStr.length === 0) return false; if (value === undefined || value === null) return false;
return queryStr.toString() === value.toString(); }, // Count results while preserving default highlighting callback(instance, row, col, data, testResult) { // Preserve the default isSearchResult flag so highlighting still works instance.getCellMeta(row, col).isSearchResult = testResult;
if (testResult) { // Custom logic: e.g., increment a result counter } }},
// Override queryMethod for a specific column only (per-cell via cascading config)columns: [ {}, { search: { queryMethod(queryStr, value) { return queryStr.toString() === value.toString(); // exact match for column 1 } } }],searchInput
options.searchInput : boolean
The searchInput option configures whether the multiSelect editor’s search input is visible.
Default: true
Category: Core
Since: 17.0.0
Example
columns: [{ type: 'multiselect', // hide the `multiSelect` editor's search input searchInput: false,}],selectionMode
options.selectionMode : string
The selectionMode option configures how selection works.
You can set the selectionMode option to one of the following:
| Setting | Description |
|---|---|
'single' | Allow the user to select only one cell at a time. |
'range' | Allow the user to select one range of cells at a time. |
'multiple' | Allow the user to select multiple ranges of cells at a time. |
Read more:
Default: “multiple”
Category: Core
Example
// you can only select one cell at at a timeselectionMode: 'single',
// you can select one range of cells at a timeselectionMode: 'range',
// you can select multiple ranges of cells at a timeselectionMode: 'multiple',selectOptions
options.selectOptions : Array<string> | object | function
The selectOptions option configures options that the end user can choose from in select cells.
You can set the selectOptions option to one of the following:
| Setting | Description |
|---|---|
| An array of strings | Each string is one option’s value and label |
| An object with key-string pairs | - Each key is one option’s value - The key’s string is that option’s label |
| A function | A function that returns an object with key-string pairs |
Read more:
Default: undefined
Category: Core
Example
columns: [ { // set the `type` of each cell in this column to `select` type: 'select', // set the first option's value and label to `A` // set the second option's value and label to `B` // set the third option's value and label to `C` selectOptions: ['A', 'B', 'C'], }, { // set the `type` of each cell in this column to `select` type: 'select', selectOptions: { // set the first option's value to `value1` and label to `Label 1` value1: 'Label 1', // set the second option's value to `value2` and label to `Label 2` value2: 'Label 2', // set the third option's value to `value3` and label to `Label 3` value3: 'Label 3', }, }, { // set the `type` of each cell in this column to `select` type: 'select', // set `selectOption` to a function that returns available options as an object selectOptions(visualRow, visualColumn, prop) { return { value1: 'Label 1', value2: 'Label 2', value3: 'Label 3', }; },],skipColumnOnPaste
options.skipColumnOnPaste : boolean
The skipColumnOnPaste option determines whether you can paste data into a given column.
You can only apply the skipColumnOnPaste option to an entire column, using the columns option. This option is not supported for the global table level settings.
You can set the skipColumnOnPaste option to one of the following:
| Setting | Description |
|---|---|
false (default) | Enable pasting data into this column |
true | - Disable pasting data into this column - On pasting, paste data into the next column to the right |
Read more:
Default: false
Category: Core
Example
columns: [ { // disable pasting data into this column skipColumnOnPaste: true }],skipRowOnPaste
options.skipRowOnPaste : boolean
The skipRowOnPaste option determines whether you can paste data into a given row.
You can only apply the skipRowOnPaste option to an entire row, using the cells option. This option is not supported for the global table level settings.
You can set the skipRowOnPaste option to one of the following:
| Setting | Description |
|---|---|
false (default) | Enable pasting data into this row |
true | - Disable pasting data into this row - On pasting, paste data into the row below |
Read more:
Default: false
Category: Core
Example
cells(row, column) { const cellProperties = {};
// disable pasting data into row 1 if (row === 1) { cellProperties.skipRowOnPaste = true; }
return cellProperties;}sortByRelevance
options.sortByRelevance : boolean
The sortByRelevance option configures whether autocomplete cells’
lists are sorted in the same order as provided in the source option.
You can set the sortByRelevance option to one of the following:
| Setting | Description |
|---|---|
true (default) | Sort options in the same order as provided in the source option |
false | Sort options alphabetically |
Read more:
Default: true
Category: Core
Example
columns: [{ // set the `type` of each cell in this column to `autocomplete` type: 'autocomplete', // set options available in every `autocomplete` cell of this column source: ['D', 'C', 'B', 'A'], // sort the `autocomplete` option in this order: D, C, B, A sortByRelevance: true}],source
options.source : Array | function
The source option sets options available in autocomplete
and dropdown cells.
You can set the source option to one of the following:
- An array of string values
- An array of objects with
keyandvalueproperties - A function
Note: When defining the source option as an array of objects with key and value properties, the data format for that cell
needs to be an object with key and value properties as well.
Read more:
Default: undefined
Category: Core
Example
// set `source` to an array of string valuescolumns: [{ // set the `type` of each cell in this column to `autocomplete` type: 'autocomplete', // set options available in every `autocomplete` cell of this column source: ['A', 'B', 'C', 'D']}],
// set `source` to an array of objects with `key` and `value` propertiescolumns: [{ // set the `type` of each cell in this column to `autocomplete` type: 'autocomplete', // set options available in every `autocomplete` cell of this column source: [{ key: 'A', value: 'Label A' }, { key: 'B', value: 'Label B' }]}],
// set `source` to a functioncolumns: [{ // set the `type` of each cell in this column to `autocomplete` type: 'autocomplete', // for every `autocomplete` cell in this column, fetch data from an external source source(query, callback) { fetch('https://example.com/query?q=' + query, function(response) { callback(response.items); }) }}],sourceDataValidator
options.sourceDataValidator : function
The sourceDataValidator option sets a function that validates values
when they are written to the source data layer. Validation runs on table initialization and when calling
loadData, updateData, or
setSourceDataAtCell. It does not run for the setData* family of methods.
Return true from the function to mark the value as valid, or false to mark it invalid. When a value is
invalid and allowInvalid is false, it is replaced with null in the
source (on initialization and when calling loadData or updateData). When allowInvalid is true, invalid
values are kept; a warning is still logged when the validator returns false. An exception:
setSourceDataAtCell - when the validator returns false, the write is
skipped and the cell is not nullified; the previous value in the source remains unchanged. Use
allowEmpty to treat null, undefined, or '' as valid when appropriate.
Optionally set sourceDataWarningMessage to customize the
message logged for invalid values.
Default: undefined
Category: Core
Since: 17.0.0
Example
sourceDataWarningMessage: 'The source data is invalid.',sourceDataValidator: (value, cellMeta) => { if (cellMeta.allowEmpty && value == null) { return true; }
if (typeof value === 'string') { return true; }
return false;}sourceDataWarningMessage
options.sourceDataWarningMessage : string
The sourceDataWarningMessage option sets the message used when
a value fails sourceDataValidator. When not set, no message is logged.
Default: undefined
Category: Core
Since: 17.0.0
Example
sourceDataWarningMessage: 'The source data is invalid.',sourceSortFunction
options.sourceSortFunction : function
The sourceSortFunction option sets a function to sort the options available in multiSelect-typed cells.
Default: undefined
Category: Core
Since: 17.0.0
Example
columns: [{ // set the `type` of each cell in this column to `multiSelect` type: 'multiselect', // set options available in every `multiSelect` cell of this column source: ['A', 'B', 'C', 'D'], // sort the `multiSelect` options in this order: D, C, B, A sourceSortFunction: (entries) => { return entries.sort((a, b) => b.localeCompare(a)); }}],startCols
options.startCols : number
If the data option is not set, the startCols option sets the initial number of empty columns.
The startCols option works only in Handsontable’s constructor and only when data is not provided.
Default: 5
Category: Core
Example
// start with 15 empty columnsstartCols: 15,startRows
options.startRows : number
If the data option is not set, the startRows option sets the initial number of empty rows.
The startRows option works only in Handsontable’s constructor and only when data is not provided.
Default: 5
Category: Core
Example
// start with 15 empty rowsstartRows: 15,stretchH
options.stretchH : string
The stretchH option determines what happens when the declared grid width
is different from the calculated sum of all column widths.
You can set the stretchH option to one of the following:
| Setting | Description |
|---|---|
'none' (default) | Don’t fit the grid to the container (disable column stretching) |
'last' | Fit the grid to the container, by stretching only the last column |
'all' | Fit the grid to the container, by stretching all columns evenly |
Read more:
Default: “none”
Category: Core
Example
// fit the grid to the container// by stretching all columns evenlystretchH: 'all',strict
options.strict : boolean
The strict option configures the behavior of autocomplete cells.
You can set the strict option to one of the following:
| Setting | Mode | Description |
|---|---|---|
true | Strict mode | The end user: - Can only choose one of suggested values - Can’t enter a custom value |
false | Flexible mode | The end user: - Can choose one of suggested values - Can enter a custom value |
This option can be set at any level of the cascading configuration:
the grid level, the columns level, the cells level, and the cell level.
Read more:
Default: undefined
Category: Core
Example
columns: [ { // set the `type` of each cell in this column to `autocomplete` type: 'autocomplete', // set options available in every `autocomplete` cell of this column source: ['A', 'B', 'C'], // values entered must match `A`, `B`, or `C` strict: true },],tableClassName
options.tableClassName : string | Array<string>
The tableClassName option lets you add CSS class names
to every Handsontable instance inside the container element.
You can set the tableClassName option to one of the following:
| Setting | Description |
|---|---|
| A string | Add a single CSS class name to every Handsontable instance inside the container element |
| An array of strings | Add multiple CSS class names to every Handsontable instance inside the container element |
Read more:
currentRowClassNamecurrentColClassNamecurrentHeaderClassNameactiveHeaderClassNameinvalidCellClassNameplaceholderCellClassNamereadOnlyCellClassNamenoWordWrapClassNamecommentedCellClassNameclassName
Default: undefined
Category: Core
Example
// add a `your-class-name` CSS class name// to every Handsontable instance inside the `container` elementtableClassName: 'your-class-name',
// add `first-class-name` and `second-class-name` CSS class names// to every Handsontable instance inside the `container` elementtableClassName: ['first-class-name', 'second-class-name'],tabMoves
options.tabMoves : object | function
The tabMoves option configures the action of the Tab key.
You can set the tabMoves option to an object with the following properties
(or to a function that returns such an object):
| Property | Type | Description |
|---|---|---|
row | Number | - On pressing Tab, move selection row rows down- On pressing Shift+Tab, move selection row rows up |
col | Number | - On pressing Tab, move selection col columns right- On pressing Shift+Tab, move selection col columns left |
Default: {row: 0, col: 1}
Category: Core
Example
// on pressing Tab, move selection 2 rows down and 2 columns right// on pressing Shift+Tab, move selection 2 rows up and 2 columns lefttabMoves: {row: 2, col: 2},
// the same setting, as a function// `event` is a DOM Event object received on pressing Tab// you can use it to check whether the user pressed Tab or Shift+TabtabMoves(event) { return {row: 2, col: 2};},tabNavigation
options.tabNavigation : boolean
When set to false, the tabNavigation option changes the behavior of the
Tab and Shift+Tab keyboard shortcuts. The Handsontable
no more captures that shortcuts to make the grid navigation available (tabNavigation: true)
but returns control to the browser so the native page navigation is possible.
Default: true
Category: Core
Since: 14.0.0
Example
// you can't navigate row and column headers using <kbd>Tab</kbd> or <kbd>Shift</kbd>+<kbd>Tab</kbd> keyboard shortcutstabNavigation: false,
// default behavior: you can navigate row and column headers using <kbd>Tab</kbd> or <kbd>Shift</kbd>+<kbd>Tab</kbd> keyboard shortcutstabNavigation: true,textEllipsis
options.textEllipsis : boolean
The textEllipsis option configures whether the text content in the cells should be truncated with an ellipsis (three dots).
You can set the textEllipsis option to one of the following:
| Setting | Description |
|---|---|
false (default) | Don’t truncate text content with an ellipsis |
true | Truncate text content with an ellipsis |
Default: false
Category: Core
Since: 16.0.0
Example
columns: [ { // truncate text content with an ellipsis textEllipsis: true, }, { // don't truncate text content with an ellipsis textEllipsis: false, }],theme
options.theme : ThemeBuilder | string | undefined
The theme option configures the visual theme for your Handsontable instance.
You can set the theme option to one of the following:
| Setting | Description |
|---|---|
undefined (default) | Don’t apply any theme and use the default main theme |
A string (e.g., 'ht-theme-horizon') | Apply a registered theme by name (required to import CSS file) |
| A plain theme config object | Apply a theme with default settings (import and pass the config, e.g. horizonTheme) |
A ThemeBuilder object | Apply a theme with runtime configuration (recommended) |
When using a ThemeBuilder object, you can configure the theme at runtime using these methods:
| Method | Description |
|---|---|
setColorScheme(mode) | Sets the color scheme: 'light', 'dark', or 'auto' (default: 'auto') |
setDensityType(type) | Sets the row density: 'compact', 'default', or 'comfortable' (default: 'default') |
params(paramsObject) | Sets custom theme parameters e.g. icons, colors, tokens |
Read more:
Default: undefined
Category: Core
Since: 17.0.0
Example
// Enable a theme by class name (requires loading the theme CSS)theme: 'ht-theme-horizon',Example
// Pass a plain theme config objectimport { horizonTheme } from 'handsontable/themes';
const hot = new Handsontable(container, { theme: horizonTheme,});Example
// Pass a ThemeBuilder object (for customization before initialization)import { horizonTheme, registerTheme } from 'handsontable/themes';
const theme = registerTheme(horizonTheme) .setColorScheme('dark') .setDensityType('compact') .params({ tokens: { fontSize: '14px', iconSize: 'size_5', borderColor: ['colors.palette.100', 'colors.palette.800'], }, });
const hot = new Handsontable(container, { theme,});themeName
options.themeName : string | undefined
The themeName option allows enabling a theme by that name.
Read more:
Default: undefined
Category: Core
Since: 15.0.0
Example
themeName: 'ht-theme-name',timeFormat
options.timeFormat : string | object
Configures the time format for time cells. Accepts either a string (legacy, for time
cells) or an object of Intl.DateTimeFormat
options (for intl-time cells).
Object form (Intl.DateTimeFormat options):
The object form is supported only when the cell type is intl-time. The locale is controlled separately
via the locale option.
Style shortcuts:
| Property | Possible values | Description |
|---|---|---|
timeStyle | 'full', 'long', 'medium', 'short' | Time formatting style (expands to hour, minute, second, timeZoneName) |
Time component options:
| Property | Possible values | Description |
|---|---|---|
hour | 'numeric', '2-digit' | Representation of the hour |
minute | 'numeric', '2-digit' | Representation of the minute |
second | 'numeric', '2-digit' | Representation of the second |
fractionalSecondDigits | 1, 2, 3 | Fraction-of-second digits |
dayPeriod | 'narrow', 'short', 'long' | Day period (e.g. “am”, “noon”) |
timeZoneName | 'long', 'short', 'shortOffset', 'longOffset', 'shortGeneric', 'longGeneric' | Time zone display |
Locale and other options:
| Property | Possible values | Description |
|---|---|---|
localeMatcher | 'best fit' (default), 'lookup' | Locale matching algorithm |
timeZone | IANA time zone (e.g. 'UTC', 'America/New_York') | Time zone for formatting |
hour12 | true, false | Use 12-hour vs 24-hour time |
hourCycle | 'h11', 'h12', 'h23', 'h24' | Hour cycle |
formatMatcher | 'basic', 'best fit' (default) | Format matching algorithm |
For complete reference, see MDN: Intl.DateTimeFormat.
Read more:
Deprecated: string form
Passing a string (e.g. 'h:mm:ss a') is deprecated and works only with the time cell type.
Migrate to the intl-time cell type and pass an Intl.DateTimeFormat options object.
Migration example:
// Before (deprecated)columns: [{ type: 'time', timeFormat: 'h:mm:ss a'}]
// After (recommended)columns: [{ type: 'intl-time', locale: 'en-US', timeFormat: { hour: 'numeric', minute: '2-digit', second: '2-digit', hour12: true }}]Default: “h:mm:ss a”
Category: Core
Example
// intl-time cell type with Intl optionscolumns: [ { type: 'intl-time', locale: 'en-US', timeFormat: { timeStyle: 'medium' } }]Example
// Legacy: time cell type with string format (deprecated)columns: [ { type: 'time', timeFormat: 'h:mm:ss a' }]title
options.title : string
The title option configures column header names.
You can set the title option to a string.
Read more:
Default: undefined
Category: Core
Example
columns: [ { // set the first column header name to `First name` title: 'First name', type: 'text', }, { // set the second column header name to `Last name` title: 'Last name', type: 'text', }],trimDropdown
options.trimDropdown : boolean
The trimDropdown option configures the width of the autocomplete
and dropdown lists.
When set to true (default), the list is trimmed to match the width of the edited cell,
which can truncate long option labels. When set to false, the list expands to fit its
longest option, which may make the list wider than the cell.
You can set the trimDropdown option to one of the following:
| Setting | Description |
|---|---|
true (default) | Make the dropdown/autocomplete list’s width the same as the edited cell’s width |
false | Scale the dropdown/autocomplete list’s width to the list’s content |
This option can be set at any level of the cascading configuration:
the grid level, the columns level, the cells level, and the cell level.
Read more:
Default: true
Category: Core
Example
columns: [ { type: 'autocomplete', // for each cell of this column // make the `autocomplete` list's width the same as the edited cell's width trimDropdown: true, }, { type: 'dropdown', // for each cell of this column // scale the `dropdown` list's width to the list's content trimDropdown: false, }],trimRows
options.trimRows : boolean | Array<number>
The trimRows option configures the TrimRows plugin.
You can set the trimRows option to one of the following:
| Setting | Description |
|---|---|
false | Disable the TrimRows plugin |
true | Enable the TrimRows plugin |
| An array of physical row indexes | - Enable the TrimRows plugin- Trim selected rows at initialization |
Read more:
Default: undefined
Category: TrimRows
Example
// enable the `TrimRows` plugintrimRows: true,
// enable the `TrimRows` plugin// at Handsontable's initialization, trim rows 5, 10, and 15trimRows: [5, 10, 15],trimWhitespace
options.trimWhitespace : boolean
The trimWhitespace option configures automatic whitespace removal. This option
affects the cell renderer and the cell editor.
You can set the trimWhitespace option to one of the following:
| Setting | Description |
|---|---|
true (default) | Remove whitespace at the beginning and at the end of each cell |
false | Don’t remove whitespace |
Default: true
Category: Core
Example
columns: [ { // don't remove whitespace // from any cell of this column trimWhitespace: false }]type
options.type : string
The type option lets you set the renderer, editor, and validator
options all at once, by selecting a cell type.
You can set the type option to one of the following:
| Cell type | Renderer, editor & validator |
|---|---|
| A custom cell type | Renderer: your custom cell renderer Editor: your custom cell editor Validator: your custom cell validator |
'autocomplete' | Renderer: AutocompleteRendererEditor: AutocompleteEditorValidator: AutocompleteValidator |
'checkbox' | Renderer: CheckboxRendererEditor: CheckboxEditorValidator: - |
'date' | Renderer: DateRendererEditor: DateEditorValidator: DateValidator |
'intl-date' | Renderer: IntlDateRendererEditor: IntlDateEditorValidator: IntlDateValidator |
'dropdown' | Renderer: DropdownRendererEditor: DropdownEditorValidator: DropdownValidator |
'handsontable' | Renderer: AutocompleteRendererEditor: HandsontableEditorValidator: - |
'numeric' | Renderer: NumericRendererEditor: NumericEditorValidator: NumericValidator |
'password' | Renderer: PasswordRendererEditor: PasswordEditorValidator: - |
'text' | Renderer: TextRendererEditor: TextEditorValidator: - |
'time’ | Renderer: TimeRendererEditor: TimeEditorValidator: TimeValidator |
'intl-time' | Renderer: IntlTimeRendererEditor: IntlTimeEditorValidator: IntlTimeValidator |
Read more:
- Cell type
- Cell renderer
- Cell editor
- Cell validator
- Configuration options: Cascading configuration
renderereditorvalidatorvalueParservalueFormatter
Default: “text”
Category: Core
Example
// set the `numeric` cell type for each cell of the entire gridtype: `'numeric'`,
// apply the `type` option to individual columnscolumns: [ { // set the `autocomplete` cell type for each cell of this column type: 'autocomplete' }, { // set the `myCustomCellType` cell type for each cell of this column type: 'myCustomCellType' }]uncheckedTemplate
options.uncheckedTemplate : boolean | string | number
The uncheckedTemplate option lets you configure what value
an unchecked checkbox cell has.
You can set the uncheckedTemplate option to one of the following:
| Setting | Description |
|---|---|
false (default) | If a checkbox cell is unchecked,the getDataAtCell method for this cell returns false |
| A string | If a checkbox cell is unchecked,the getDataAtCell method for this cell returns a string of your choice |
This option can be set at any level of the cascading configuration:
the grid level, the columns level, the cells level, and the cell level.
Read more:
Default: false
Category: Core
Example
columns: [ { // set the `type` of each cell in this column to `checkbox` // when unchecked, the cell's value is `false` // when checked, the cell's value is `true` type: 'checkbox', }, { // set the `type` of each cell in this column to `checkbox` // when unchecked, the cell's value is `'No'` // when checked, the cell's value is `'Yes'` type: 'checkbox', uncheckedTemplate: 'No' checkedTemplate: 'Yes', }],undo
options.undo : boolean
The undo option configures the UndoRedo plugin.
You can set the undo option to one of the following:
By default, the undo option is set to true,
To disable the UndoRedo plugin completely,
set the undo option to false.
Read more:
Default: undefined
Category: UndoRedo
Example
// enable the `UndoRedo` pluginundo: true,validator
options.validator : function | RegExp | string
The validator option sets a cell validator for a cell.
You can set the validator option to one of the following:
| Setting | Description |
|---|---|
| A string | A cell validator alias |
| A function | Your custom cell validator function |
| A regular expression | A regular expression used for cell validation |
This option can be set at any level of the cascading configuration:
the grid level, the columns level, the cells level, and the cell level.
By setting the validator option to a string,
you can use one of the following cell validator aliases:
| Alias | Cell validator function |
|---|---|
| A custom alias | Your custom cell validator |
'autocomplete' | AutocompleteValidator |
'date' | DateValidator |
'intl-date' | IntlDateValidator |
'dropdown' | DropdownValidator |
'numeric' | NumericValidator |
'time' | TimeValidator |
'intl-time' | IntlTimeValidator |
To set the editor, renderer, and validator
options all at once, use the type option.
Read more:
Default: undefined
Category: Core
Example
columns: [ { // use a built-in `numeric` cell validator validator: 'numeric' }, { // validate against a regular expression validator: /^[0-9]$/ }, { // add a custom cell validator function validator(value, callback) { ... } },],valueFormatter
options.valueFormatter : function
The valueFormatter option sets a custom function for formatting cell values before display.
Unlike the renderer option, which is responsible for the complete cell rendering process
(DOM structure, performance-optimized content insertion via innerText/innerHTML, a11y attributes, applying
styles from className, readOnlyCellClassName, textEllipsis, and other options), the valueFormatter
focuses solely on transforming the cell’s value.
The valueFormatter function is called by the rendering engine right before the actual renderer function is
called. Separating the value formatting from the renderer logic allows for more flexibility and reuse.
This simplifies common formatting use cases where you only need to transform
the displayed value (e.g., adding units, formatting dates, or applying custom text transformations).
When to use valueFormatter vs renderer:
| Use case | Recommended option |
|---|---|
| Transform displayed value (add prefix, units) | valueFormatter |
| Custom date/number/text formatting | valueFormatter |
| Modify DOM structure (add icons, custom elements) | renderer |
The function receives the raw value and cell properties, and should return the formatted value to be displayed. The formatting can be applied to a single cell, column, or the entire grid.
Function signature:
valueFormatter(value, cellProperties) => formattedValue| Parameter | Type | Description |
|---|---|---|
value | * | The raw cell value |
cellProperties | object | The cell’s meta object (see Core#getCellMeta) |
| Returns | * | The formatted value to display |
Read more:
Default: undefined
Category: Core
Since: 17.0.0
Example
// add a currency symbol to numeric valuesvalueFormatter(value, cellProperties) { if (value === null || value === undefined) { return ''; }
return `$${value}`;}
// format dates in a custom formatvalueFormatter(value, cellProperties) { if (!value) { return ''; }
const date = new Date(value);
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });}
// apply valueFormatter to individual columnscolumns: [ { // add "kg" suffix to weight values valueFormatter(value) { return value ? `${value} kg` : ''; } }, { // format percentages valueFormatter(value) { return value !== null ? `${(value * 100).toFixed(1)}%` : ''; } }]valueGetter
options.valueGetter : function
The valueGetter option configures a function that defines what value will be used when displaying the cell content.
It can be used to modify the value of a cell before it is displayed (for example, for object-based data).
Default: undefined
Category: Core
Since: 16.1.0
Example
// use the `label` property of the value object with a fallback to the value itselfvalueGetter: (value, row, column, cellMeta) => { return value?.label ?? value;}| Param | Type | Description |
|---|---|---|
| value | * | The value to be displayed in the cell. |
| row | number | The visual row index of the cell. |
| column | number | The visual column index of the cell. |
| cellMeta | object | The cell meta object. |
valueParser
options.valueParser : function
The valueParser option sets a custom function for converting editor output into the source data format.
Unlike valueFormatter, which formats values for display, valueParser runs only when a
value comes from the cell editor - after the user finishes
editing. It maps whatever the editor returns (e.g. a localized date string, a formatted number) into the
canonical shape stored in the data source (e.g. ISO date string, raw number).
When to use valueParser vs valueFormatter:
| Use case | Option |
|---|---|
| Display: raw value -> shown text | valueFormatter |
| Edit: editor value -> source data | valueParser |
Function signature:
valueParser(value, cellProperties) => sourceValue| Parameter | Type | Description |
|---|---|---|
value | * | The value produced by the editor |
cellProperties | object | The cell’s meta object (see Core#getCellMeta) |
| Returns | * | The value to store in the source data |
Read more:
- Cell editor
editorrenderervalueFormattersourceDataValidator- Configuration options: Cascading configuration
Default: undefined
Category: Core
Since: 17.0.0
Example
// parse editor string to ISO date (e.g. intl-date: display format => source format)valueParser(value, cellProperties) { if (value == null || value === '') { return null; }
const date = new Date(value);
return Number.isNaN(date.getTime()) ? value : date.toISOString().slice(0, 10);}
// parse formatted number string to numbervalueParser(value, cellProperties) { if (value == null || value === '') { return null; }
const num = Number(value.replace(/[^\d.-]/g, ''));
return Number.isNaN(num) ? value : num;}
// apply valueParser per columncolumns: [ { data: 'date', valueParser: (value) => value ? new Date(value).toISOString().slice(0, 10) : null }, { data: 'amount', valueParser: (value) => value != null ? Number(value) : null }]valueSetter
options.valueSetter : function
The valueSetter option configures a function that defines what value will be used when setting the cell content.
It can be used to modify the value of a cell before it is saved (for example, for object-based data).
Default: undefined
Category: Core
Since: 16.1.0
Example
// Modify the value of a cell before it is savedvalueSetter: (value, row, column, cellMeta) => { return { id: value?.id ?? value, value: `${value?.value ?? value} at ${row}, ${column}` }},| Param | Type | Description |
|---|---|---|
| value | * | The value to be set to a cell. |
| row | number | The visual row index of the cell. |
| column | number | The visual column index of the cell. |
| cellMeta | object | The cell meta object. |
viewportColumnRenderingOffset
options.viewportColumnRenderingOffset : number | ‘auto’
The viewportColumnRenderingOffset option configures the number of columns
to be rendered outside of the grid’s viewport.
You can set the viewportColumnRenderingOffset option to one of the following:
| Setting | Description |
|---|---|
auto (default) | Use the offset calculated automatically by Handsontable |
| A number | Set the offset manually |
The viewportColumnRenderingOffset setting is ignored when renderAllColumns is set to true.
Read more:
Default: ‘auto’
Category: Core
Example
// render 70 columns outside of the grid's viewportviewportColumnRenderingOffset: 70,viewportColumnRenderingThreshold
options.viewportColumnRenderingThreshold : number | ‘auto’
The viewportColumnRenderingThreshold option configures what column number starting from the left or right
(depends on the scroll direction) should trigger the rendering of columns outside of the grid’s viewport.
You can set the viewportColumnRenderingThreshold option to one of the following:
| Setting | Description |
|---|---|
auto | Triggers rendering at half the offset defined by viewportColumnRenderingOffset option |
| A number | Sets the offset manually (0 is a default) |
The viewportColumnRenderingThreshold setting is ignored when renderAllColumn is set to true.
Read more:
Default: 0
Category: Core
Since: 1.14.7
Example
// render 12 columns outside of the grid's viewportviewportColumnRenderingOffset: 12,// the columns outside of the viewport will be rendered when the user scrolls to the 8th column from/toviewportColumnRenderingThreshold: 8,viewportRowRenderingOffset
options.viewportRowRenderingOffset : number | ‘auto’
The viewportRowRenderingOffset option configures the number of rows
to be rendered outside of the grid’s viewport.
You can set the viewportRowRenderingOffset option to one of the following:
| Setting | Description |
|---|---|
auto (default) | Use the offset calculated automatically by Handsontable |
| A number | Set the offset manually |
The viewportRowRenderingOffset setting is ignored when renderAllRows is set to true.
Read more:
Default: ‘auto’
Category: Core
Example
// render 70 rows outside of the grid's viewportviewportRowRenderingOffset: 70,viewportRowRenderingThreshold
options.viewportRowRenderingThreshold : number | ‘auto’
The viewportRowRenderingThreshold option configures what row number starting from the top or bottom
(depends on the scroll direction) should trigger the rendering of rows outside of the grid’s viewport.
You can set the viewportRowRenderingThreshold option to one of the following:
| Setting | Description |
|---|---|
auto | Triggers rendering at half the offset defined by viewportRowRenderingOffset option |
| A number | Sets the offset manually (0 is a default) |
The viewportRowRenderingThreshold setting is ignored when renderAllRows is set to true.
Read more:
Default: 0
Category: Core
Since: 1.14.7
Example
// render 12 rows outside of the grid's viewportviewportRowRenderingOffset: 12,// the rows outside of the viewport will be rendered when the user scrolls to the 8th row from/toviewportRowRenderingThreshold: 8,visibleRows
options.visibleRows : number
The visibleRows option sets the height of the autocomplete
, dropdown and multiSelect-typed cells’ lists.
When the number of list options exceeds the visibleRows number, a scrollbar appears.
This option can be set at any level of the cascading configuration:
the grid level, the columns level, the cells level, and the cell level.
Read more:
Default: 10
Category: Core
Example
columns: [ { type: 'autocomplete', // set the `autocomplete` list's height to 15 options // for each cell of this column visibleRows: 15, }, { type: 'dropdown', // set the `dropdown` list's height to 5 options // for each cell of this column visibleRows: 5, }, { type: 'multiselect', // set the `multiSelect` list's height to 5 options // for each cell of this column visibleRows: 5, }],width
options.width : number | ‘auto’ | string | function
The width option configures the width of your grid.
You can set the width option to one of the following:
| Setting | Example |
|---|---|
| A number of pixels | width: 500 |
| A string with a CSS unit | width: '75vw' |
'auto' | width: 'auto' |
| A function that returns a valid number or string | width() { return 500; } |
With width: 'auto', Handsontable writes width: auto as an inline style on the root
element. The grid then follows the width of its parent container. Use this value when
you want the grid to stay flexible horizontally while still setting an explicit
height.
Read more:
Default: undefined
Category: Core
Example
// set the grid's width to 500pxwidth: 500,
// set the grid's width to 75vwwidth: '75vw',
// let the grid follow its parent container's widthwidth: 'auto',
// set the grid's width to 500px, using a functionwidth() { return 500;},wordWrap
options.wordWrap : boolean
The wordWrap option configures whether content that exceeds a column’s width is wrapped or not.
You can set the wordWrap option to one of the following:
| Setting | Description |
|---|---|
true (default) | If content exceeds the column’s width, wrap the content |
false | Don’t wrap content |
To style cells that don’t wrap content, use the noWordWrapClassName option.
This option can be set at any level of the cascading configuration:
the grid level, the columns level, the cells level, and the cell level.
Read more:
Default: true
Category: Core
Example
// set column width for every column of the entire gridcolWidths: 100,
columns: [ { // don't wrap content in this column wordWrap: false, }, { // if content exceeds this column's width, wrap the content wordWrap: true, }],Methods
isEmptyCol
options.isEmptyCol(col) ⇒ boolean
The isEmptyCol option lets you define your own custom method
for checking if a column at a given visual index is empty.
The isEmptyCol setting overwrites the built-in isEmptyCol method.
The function receives a visual column index and must return a boolean.
This option can only be set at the grid level.
It has no effect when set in the columns, cells, or cell options.
Category: Core
Example
// overwrite the built-in `isEmptyCol` methodisEmptyCol(visualColumnIndex) { // your custom method ...},| Param | Type | Description |
|---|---|---|
| col | number | Visual column index. |
isEmptyRow
options.isEmptyRow(row) ⇒ boolean
The isEmptyRow option lets you define your own custom method
for checking if a row at a given visual index is empty.
The isEmptyRow setting overwrites the built-in isEmptyRow method.
The function receives a visual row index and must return a boolean.
This option can only be set at the grid level.
It has no effect when set in the columns, cells, or cell options.
Category: Core
Example
// overwrite the built-in `isEmptyRow` methodisEmptyRow(visualRowIndex) { // your custom method ...},| Param | Type | Description |
|---|---|---|
| row | number | Visual row index. |