Skip to content

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.

Basic example

JavaScript
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.
registerAllModules();
const colorData = [['yellow'], ['red'], ['orange'], ['green'], ['blue'], ['gray'], ['black'], ['white']];
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)
return this.getSourceDataAtRow(Math.max(selection[0], 0)).name;
},
},
},
{ type: 'numeric' },
{
type: 'handsontable',
handsontable: {
colHeaders: false,
data: colorData,
},
},
{
type: 'handsontable',
handsontable: {
colHeaders: false,
data: colorData,
},
},
],
autoWrapRow: true,
autoWrapCol: true,
});
TypeScript
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 colorData: [string][] = [['yellow'], ['red'], ['orange'], ['green'], ['blue'], ['gray'], ['black'], ['white']];
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)
return this.getSourceDataAtRow(Math.max(selection[0], 0)).name;
},
},
},
{ type: 'numeric' },
{
type: 'handsontable',
handsontable: {
colHeaders: false,
data: colorData,
},
},
{
type: 'handsontable',
handsontable: {
colHeaders: false,
data: colorData,
},
},
],
autoWrapRow: true,
autoWrapCol: true,
});

Keyboard shortcuts

KeyAction
EscapeClose editor and cancel change
EnterClose editor and apply change; move selection in the main HOT downwards or according to the enterMoves setting
TabSame as Enter, but move selection to the right or left according to the tabMoves setting
Arrow DownMove selection in HOT-in-HOT downwards. No effect if last row is selected
Arrow UpMove 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 RightMove 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 LeftMove text cursor in the text field to the right. If cursor was at end, behave as Tab

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 guides

Configuration options

Core methods

Hooks