Handsontable cell type
Add a spreadsheet editor in a popup, by using the Handsontable cell type.
The Handsontable cell type embeds a second grid instance as a cell editor (HOT-in-HOT). Use it when users need to search and select from a large dataset.
Usage
HOT-in-HOT opens by any of the following:
- F2 or Enter key is pressed while the cell is selected
- The triangle icon is clicked
- The cell content is double clicked
While HOT-in-HOT is opened, the text field above the HOT-in-HOT remains focused at all times.
The nested grid is not the main grid, so the options that drive main-grid UI have no effect when you set them inside the handsontable option: dialog, notification, emptyDataState, pagination, and loading. Set them on the main grid instead. The same applies to the nested grid that the autocomplete and dropdown cell types open.
Basic example
The first column uses the handsontable cell type for a searchable manufacturer list. The color columns use the dropdown cell type for compact selection from a short list.
import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';// Register all Handsontable's modules.registerAllModules();const manufacturerData = [ { name: 'BMW', country: 'Germany', owner: 'Bayerische Motoren Werke AG' }, { name: 'Chrysler', country: 'USA', owner: 'Chrysler Group LLC' }, { name: 'Nissan', country: 'Japan', owner: 'Nissan Motor Company Ltd' }, { name: 'Suzuki', country: 'Japan', owner: 'Suzuki Motor Corporation' }, { name: 'Toyota', country: 'Japan', owner: 'Toyota Motor Corporation' }, { name: 'Volvo', country: 'Sweden', owner: 'Zhejiang Geely Holding Group' },];const container = document.querySelector('#example1');new Handsontable(container, { height: 'auto', licenseKey: 'non-commercial-and-evaluation', data: [ ['Tesla', 2017, 'black', 'black'], ['Nissan', 2018, 'blue', 'blue'], ['Chrysler', 2019, 'yellow', 'black'], ['Volvo', 2020, 'white', 'gray'], ], colHeaders: ['Car', 'Year', 'Chassis color', 'Bumper color'], columns: [ { type: 'handsontable', handsontable: { colHeaders: ['Marque', 'Country', 'Parent company'], autoColumnSize: true, data: manufacturerData, getValue() { const selection = this.getSelectedLast(); // Get the manufacturer name of the clicked row and ignore header // coordinates (negative values) const row = this.getSourceDataAtRow(Math.max(selection?.[0] ?? 0, 0)); return row.name; }, }, }, { type: 'numeric' }, { type: 'dropdown', source: ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white'], }, { type: 'dropdown', source: ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white'], }, ], autoWrapRow: true, autoWrapCol: true,});import Handsontable from 'handsontable/base';import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.registerAllModules();
interface Manufacturer { name: string; country: string; owner: string;}
const manufacturerData: Manufacturer[] = [ { name: 'BMW', country: 'Germany', owner: 'Bayerische Motoren Werke AG' }, { name: 'Chrysler', country: 'USA', owner: 'Chrysler Group LLC' }, { name: 'Nissan', country: 'Japan', owner: 'Nissan Motor Company Ltd' }, { name: 'Suzuki', country: 'Japan', owner: 'Suzuki Motor Corporation' }, { name: 'Toyota', country: 'Japan', owner: 'Toyota Motor Corporation' }, { name: 'Volvo', country: 'Sweden', owner: 'Zhejiang Geely Holding Group' },];
const container = document.querySelector('#example1')!;
new Handsontable(container, { height: 'auto', licenseKey: 'non-commercial-and-evaluation', data: [ ['Tesla', 2017, 'black', 'black'], ['Nissan', 2018, 'blue', 'blue'], ['Chrysler', 2019, 'yellow', 'black'], ['Volvo', 2020, 'white', 'gray'], ], colHeaders: ['Car', 'Year', 'Chassis color', 'Bumper color'], columns: [ { type: 'handsontable', handsontable: { colHeaders: ['Marque', 'Country', 'Parent company'], autoColumnSize: true, data: manufacturerData, getValue() { const selection = this.getSelectedLast();
// Get the manufacturer name of the clicked row and ignore header // coordinates (negative values) const row = this.getSourceDataAtRow(Math.max(selection?.[0] ?? 0, 0)) as { name: string };
return row.name; }, }, }, { type: 'numeric' }, { type: 'dropdown', source: ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white'], }, { type: 'dropdown', source: ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white'], }, ], autoWrapRow: true, autoWrapCol: true,});Keyboard shortcuts
| Key | Action |
|---|---|
| Escape | Close editor and cancel change |
| Enter | Close editor and apply change; move selection in the main HOT downwards or according to the enterMoves setting |
| Tab | Same as Enter, but move selection to the right or left according to the tabMoves setting |
| Arrow Down | Move selection in HOT-in-HOT downwards. No effect if last row is selected |
| Arrow Up | Move selection in HOT-in-HOT upwards. If the first row was selected, deselect. If HOT-in-HOT was deselected, behave as Enter but move main HOT selection upwards |
| Arrow Right | Move text cursor in the text field to the left. If cursor was at start, behave as Enter but move main HOT selection to the left |
| Arrow Left | Move text cursor in the text field to the right. If cursor was at end, behave as Tab |
For the full list of default keyboard shortcuts, see keyboard shortcuts.
Result
After configuring the Handsontable cell type, cells display a text input with a trigger icon. Activating the cell opens a second embedded grid that users can navigate and select from. The selected row value is written back to the parent cell.
Related articles
Related guides
Configuration options
Core methods
Hooks