Autocomplete cell type
Collect user input with a list of choices, by using the autocomplete cell type.
Overview
You can edit the autocomplete-typed cells in three different ways:
- Flexible mode
- Strict mode
- Strict mode using Ajax
In all three modes, the source option can be provided in two formats:
- An array of values
- An array of objects with
keyandvalueproperties
Autocomplete flexible mode
This example uses the autocomplete feature in the default flexible mode. In this mode, the user can choose one of the suggested options while typing or enter a custom value that is not included in the suggestions.
/* file: app.component.ts */import { Component } from '@angular/core';import { GridSettings } from '@handsontable/angular-wrapper';
const colors = [ 'yellow', 'red', 'orange and another color', 'green', 'blue', 'gray', 'black', 'white', 'purple', 'lime', 'olive', 'cyan',];
@Component({ selector: 'example1-autocomplete-cell-type', standalone: false, template: ` <div> <hot-table [data]="data" [settings]="gridSettings"></hot-table> </div>`,})export class Example1AutocompleteCellTypeComponent {
readonly data = [ ['BMW', 2017, 'black', 'black'], ['Nissan', 2018, 'blue', 'blue'], ['Chrysler', 2019, 'yellow', 'black'], ['Volvo', 2020, 'white', 'gray'], ];
readonly gridSettings: GridSettings = { height: 'auto', colHeaders: ['Car', 'Year', 'Chassis color', 'Bumper color'], autoWrapRow: true, autoWrapCol: true, columns: [ { type: 'autocomplete', source: ['BMW', 'Chrysler', 'Nissan', 'Suzuki', 'Toyota', 'Volvo'], strict: false, }, { type: 'numeric' }, { type: 'autocomplete', source: colors, strict: false, visibleRows: 4, }, { type: 'autocomplete', source: colors, strict: false, trimDropdown: false, }, ] };}/* end-file */
/* file: app.module.ts */import { NgModule, ApplicationConfig } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { registerAllModules } from 'handsontable/registry';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, HotTableModule } from '@handsontable/angular-wrapper';import { CommonModule } from '@angular/common';import { NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';/* start:skip-in-compilation */import { Example1AutocompleteCellTypeComponent } from './app.component';/* end:skip-in-compilation */
// register Handsontable's modulesregisterAllModules();
export const appConfig: ApplicationConfig = { providers: [ { provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE, } as HotGlobalConfig } ],};
@NgModule({ imports: [ BrowserModule, HotTableModule, CommonModule ], declarations: [ Example1AutocompleteCellTypeComponent ], providers: [...appConfig.providers], bootstrap: [ Example1AutocompleteCellTypeComponent ]})
export class AppModule { }/* end-file */<div> <example1-autocomplete-cell-type></example1-autocomplete-cell-type></div>Autocomplete strict mode
This is the same example as above, the difference being that autocomplete now runs in strict mode. In this mode, the autocomplete cells will only accept values that are defined in the source array. The mouse and keyboard bindings are identical to the Handsontable cell type but with the differences below:
- If there is at least one option visible, there always is a selection in HOT-in-HOT
- When the first row is selected, pressing Arrow Up does not deselect HOT-in-HOT. Instead, it behaves as the Enter key but moves the selection in the main HOT upwards
In strict mode, the allowInvalid option determines the behaviour in the case of manual user input:
allowInvalid: trueoptional - allows manual input of a value that does not exist in thesource, the field background is highlighted in red, and the selection advances to the next cellallowInvalid: false- does not allow manual input of a value that does not exist in thesource, the Enter key is ignored, and the editor field remains open
/* file: app.component.ts */import { Component } from '@angular/core';import { GridSettings } from '@handsontable/angular-wrapper';
const colors = [ 'yellow', 'red', 'orange and another color', 'green', 'blue', 'gray', 'black', 'white', 'purple', 'lime', 'olive', 'cyan',];
@Component({ selector: 'example2-autocomplete-cell-type', standalone: false, template: ` <div> <hot-table [data]="data" [settings]="gridSettings"></hot-table> </div>`,})export class Example2AutocompleteCellTypeComponent {
readonly data = [ ['BMW', 2017, 'black', 'black'], ['Nissan', 2018, 'blue', 'blue'], ['Chrysler', 2019, 'yellow', 'black'], ['Volvo', 2020, 'white', 'gray'], ];
readonly gridSettings: GridSettings = { height: 'auto', colHeaders: [ 'Car<br>(allowInvalid true)', 'Year', 'Chassis color', 'Bumper color<br>(allowInvalid true)', ], autoWrapRow: true, autoWrapCol: true, columns: [ { type: 'autocomplete', source: ['BMW', 'Chrysler', 'Nissan', 'Suzuki', 'Toyota', 'Volvo'], strict: true, }, {}, { type: 'autocomplete', source: colors, strict: true, }, { type: 'autocomplete', source: colors, strict: true, allowInvalid: true, // true is default }, ] };}/* end-file */
/* file: app.module.ts */import { NgModule, ApplicationConfig } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { registerAllModules } from 'handsontable/registry';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, HotTableModule } from '@handsontable/angular-wrapper';import { CommonModule } from '@angular/common';import { NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';/* start:skip-in-compilation */import { Example2AutocompleteCellTypeComponent } from './app.component';/* end:skip-in-compilation */
// register Handsontable's modulesregisterAllModules();
export const appConfig: ApplicationConfig = { providers: [ { provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE, } as HotGlobalConfig } ],};
@NgModule({ imports: [ BrowserModule, HotTableModule, CommonModule ], declarations: [ Example2AutocompleteCellTypeComponent ], providers: [...appConfig.providers], bootstrap: [ Example2AutocompleteCellTypeComponent ]})
export class AppModule { }/* end-file */<div> <example2-autocomplete-cell-type></example2-autocomplete-cell-type></div>Autocomplete strict mode (Ajax)
Autocomplete can also be used with Ajax data sources. In the example below, suggestions for the “Car” column are loaded from the server. To load data from a remote asynchronous source, assign a function to the ‘source’ property. The function should perform the server-side request and call the callback function when the result is available.
/* file: app.component.ts */import { Component } from '@angular/core';import { GridSettings } from '@handsontable/angular-wrapper';
@Component({ selector: 'example3-autocomplete-cell-type', standalone: false, template: ` <div> <hot-table [data]="data" [settings]="gridSettings"></hot-table> </div>`})export class Example3AutocompleteCellTypeComponent {
readonly data = [ ['BMW', 2017, 'black', 'black'], ['Nissan', 2018, 'blue', 'blue'], ['Chrysler', 2019, 'yellow', 'black'], ['Volvo', 2020, 'white', 'gray'], ];
readonly gridSettings: GridSettings = { height: 'auto', colHeaders: ['Car', 'Year', 'Chassis color', 'Bumper color'], autoWrapRow: true, autoWrapCol: true, columns: [ { type: 'autocomplete', source: (_query, process) => { fetch('https://handsontable.com/docs/scripts/json/autocomplete.json') .then((response) => response.json()) .then((response) => process(response.data)); }, strict: true, }, {}, // Year is a default text column {}, // Chassis color is a default text column {}, // Bumper color is a default text column ] };}/* end-file */
/* file: app.module.ts */import { NgModule, ApplicationConfig } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { registerAllModules } from 'handsontable/registry';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, HotTableModule } from '@handsontable/angular-wrapper';import { CommonModule } from '@angular/common';import { NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';/* start:skip-in-compilation */import { Example3AutocompleteCellTypeComponent } from './app.component';/* end:skip-in-compilation */
// register Handsontable's modulesregisterAllModules();
export const appConfig: ApplicationConfig = { providers: [ { provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE, } as HotGlobalConfig } ],};
@NgModule({ imports: [ BrowserModule, HotTableModule, CommonModule ], declarations: [ Example3AutocompleteCellTypeComponent ], providers: [...appConfig.providers], bootstrap: [ Example3AutocompleteCellTypeComponent ]})
export class AppModule { }/* end-file */<div> <example3-autocomplete-cell-type></example3-autocomplete-cell-type></div>The source option
The source option can be provided in two formats:
Array of values
You can provide the source option as an array of values that will be used as the autocomplete suggestions.
/* file: app.component.ts */import { Component } from '@angular/core';import { GridSettings } from '@handsontable/angular-wrapper';
@Component({ selector: 'example4-autocomplete-cell-type', standalone: false, template: ` <div> <hot-table [data]="shipmentKVData" [settings]="gridSettings"></hot-table> </div>`})export class Example4AutocompleteCellTypeComponent { readonly shipmentKVData = [ ['Electronics and Gadgets','Los Angeles International Airport'], ['Medical Supplies', 'John F. Kennedy International Airport'], ['Auto Parts', 'Chicago O\'Hare International Airport'], ['Fresh Produce', 'London Heathrow Airport'], ['Textiles', 'Charles de Gaulle Airport'], ['Industrial Equipment', 'Dubai International Airport'], ['Pharmaceuticals', 'Tokyo Haneda Airport'], ['Consumer Goods', 'Beijing Capital International Airport'], ['Machine Parts', 'Singapore Changi Airport'], ['Food Products', 'Amsterdam Airport Schiphol'] ];
readonly airportKVData = [ 'Los Angeles International Airport', 'John F. Kennedy International Airport', 'Chicago O\'Hare International Airport', 'London Heathrow Airport', 'Charles de Gaulle Airport', 'Dubai International Airport', 'Tokyo Haneda Airport', 'Beijing Capital International Airport', 'Singapore Changi Airport', 'Amsterdam Airport Schiphol', 'Frankfurt Airport', 'Seoul Incheon International Airport', 'Toronto Pearson International Airport', 'Madrid-Barajas Airport', 'Bangkok Suvarnabhumi Airport', 'Munich International Airport', 'Sydney Kingsford Smith Airport', 'Barcelona-El Prat Airport', 'Kuala Lumpur International Airport', 'Zurich Airport' ];
readonly gridSettings: GridSettings = { height: 'auto', autoWrapRow: true, autoWrapCol: true, columns: [ { title: 'Shipment', }, { type: 'autocomplete', source: this.airportKVData, title: 'Airport', }, ], };}/* end-file */
/* file: app.module.ts */import { NgModule, ApplicationConfig } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { registerAllModules } from 'handsontable/registry';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, HotTableModule } from '@handsontable/angular-wrapper';import { CommonModule } from '@angular/common';import { NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';/* start:skip-in-compilation */import { Example4AutocompleteCellTypeComponent } from './app.component';/* end:skip-in-compilation */
// register Handsontable's modulesregisterAllModules();
export const appConfig: ApplicationConfig = { providers: [ { provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE, } as HotGlobalConfig } ],};
@NgModule({ imports: [ BrowserModule, HotTableModule, CommonModule ], declarations: [ Example4AutocompleteCellTypeComponent ], providers: [...appConfig.providers], bootstrap: [ Example4AutocompleteCellTypeComponent ]})
export class AppModule { }/* end-file */<div> <example4-autocomplete-cell-type></example4-autocomplete-cell-type></div>Array of objects
You can provide the source option as an array of objects with key and value properties. The value property will be used as the autocomplete suggestion, while the entire object will be used as the value of the cell.
/* file: app.component.ts */import { Component } from '@angular/core';import { GridSettings } from '@handsontable/angular-wrapper';
@Component({ selector: 'example5-autocomplete-cell-type', standalone: false, template: ` <div> <hot-table [data]="shipmentKVData" [settings]="gridSettings"></hot-table> </div>`})export class Example5AutocompleteCellTypeComponent { readonly shipmentKVData = [ [ 'Electronics and Gadgets', { key: 'LAX', value: 'Los Angeles International Airport' }, ], [ 'Medical Supplies', { key: 'JFK', value: 'John F. Kennedy International Airport' } ], [ 'Auto Parts', { key: 'ORD', value: 'Chicago O\'Hare International Airport' } ], [ 'Fresh Produce', { key: 'LHR', value: 'London Heathrow Airport' } ], [ 'Textiles', { key: 'CDG', value: 'Charles de Gaulle Airport' } ], [ 'Industrial Equipment', { key: 'DXB', value: 'Dubai International Airport' } ], [ 'Pharmaceuticals', { key: 'HND', value: 'Tokyo Haneda Airport' } ], [ 'Consumer Goods', { key: 'PEK', value: 'Beijing Capital International Airport' } ], [ 'Machine Parts', { key: 'SIN', value: 'Singapore Changi Airport' } ], [ 'Food Products', { key: 'AMS', value: 'Amsterdam Airport Schiphol' } ] ];
readonly airportKVData = [ { key: 'LAX', value: 'Los Angeles International Airport' }, { key: 'JFK', value: 'John F. Kennedy International Airport' }, { key: 'ORD', value: 'Chicago O\'Hare International Airport' }, { key: 'LHR', value: 'London Heathrow Airport' }, { key: 'CDG', value: 'Charles de Gaulle Airport' }, { key: 'DXB', value: 'Dubai International Airport' }, { key: 'HND', value: 'Tokyo Haneda Airport' }, { key: 'PEK', value: 'Beijing Capital International Airport' }, { key: 'SIN', value: 'Singapore Changi Airport' }, { key: 'AMS', value: 'Amsterdam Airport Schiphol' }, { key: 'FRA', value: 'Frankfurt Airport' }, { key: 'ICN', value: 'Seoul Incheon International Airport' }, { key: 'YYZ', value: 'Toronto Pearson International Airport' }, { key: 'MAD', value: 'Madrid-Barajas Airport' }, { key: 'BKK', value: 'Bangkok Suvarnabhumi Airport' }, { key: 'MUC', value: 'Munich International Airport' }, { key: 'SYD', value: 'Sydney Kingsford Smith Airport' }, { key: 'BCN', value: 'Barcelona-El Prat Airport' }, { key: 'KUL', value: 'Kuala Lumpur International Airport' }, { key: 'ZRH', value: 'Zurich Airport' } ];
readonly gridSettings: GridSettings = { height: 'auto', autoWrapRow: true, autoWrapCol: true, columns: [ { title: 'Shipment', }, { type: 'autocomplete', source: this.airportKVData, title: 'Airport', }, ], };}/* end-file */
/* file: app.module.ts */import { NgModule, ApplicationConfig } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { registerAllModules } from 'handsontable/registry';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, HotTableModule } from '@handsontable/angular-wrapper';import { CommonModule } from '@angular/common';import { NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';/* start:skip-in-compilation */import { Example5AutocompleteCellTypeComponent } from './app.component';/* end:skip-in-compilation */
// register Handsontable's modulesregisterAllModules();
export const appConfig: ApplicationConfig = { providers: [ { provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE, } as HotGlobalConfig } ],};
@NgModule({ imports: [ BrowserModule, HotTableModule, CommonModule ], declarations: [ Example5AutocompleteCellTypeComponent ], providers: [...appConfig.providers], bootstrap: [ Example5AutocompleteCellTypeComponent ]})
export class AppModule { }/* end-file */<div> <example5-autocomplete-cell-type></example5-autocomplete-cell-type></div>API methods
When working with object-based autocomplete data, you can use methods like getSourceData(), getSourceDataAtCell(), getSourceDataAtRow() etc., to get the data in its original object format with both key and value properties. The getData() method will return only the value property’s value.
The filter option
By default, the autocomplete dropdown hides options that don’t match what the user is typing. Set filter: false to always show the full list of source options, regardless of the current input. This is useful when you want to give users a visual reference of all available choices while they type.
The left column uses the default behavior (filter: true) — options are narrowed as you type. The right column has filter: false — all options remain visible no matter what you enter.
/* file: app.component.ts */import { Component } from '@angular/core';import { GridSettings } from '@handsontable/angular-wrapper';
@Component({ selector: 'example6-autocomplete-cell-type', standalone: false, template: ` <div> <hot-table [data]="data" [settings]="gridSettings"></hot-table> </div>`})export class Example6AutocompleteCellTypeComponent { readonly fruits = [ 'Apple', 'Apricot', 'Avocado', 'Banana', 'Blueberry', 'Cherry', 'Grape', 'Lemon', 'Lime', 'Mango', 'Orange', 'Peach', 'Pear', 'Pineapple', 'Plum', 'Raspberry', 'Strawberry', 'Watermelon', ];
readonly data = [ ['Apple', 'Apple'], ['Banana', 'Banana'], ['Cherry', 'Cherry'], ['Mango', 'Mango'], ['Orange', 'Orange'], ];
readonly gridSettings: GridSettings = { height: 'auto', autoWrapRow: true, autoWrapCol: true, colHeaders: ['Filter: true (default)', 'Filter: false'], columns: [ { type: 'autocomplete', source: this.fruits, strict: false, }, { type: 'autocomplete', source: this.fruits, strict: false, // don't hide options that don't match the search query filter: false, }, ], };}/* end-file */
/* file: app.module.ts */import { NgModule, ApplicationConfig } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { registerAllModules } from 'handsontable/registry';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, HotTableModule } from '@handsontable/angular-wrapper';import { CommonModule } from '@angular/common';import { NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';/* start:skip-in-compilation */import { Example6AutocompleteCellTypeComponent } from './app.component';/* end:skip-in-compilation */
// register Handsontable's modulesregisterAllModules();
export const appConfig: ApplicationConfig = { providers: [ { provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE, } as HotGlobalConfig } ],};
@NgModule({ imports: [ BrowserModule, HotTableModule, CommonModule ], declarations: [ Example6AutocompleteCellTypeComponent ], providers: [...appConfig.providers], bootstrap: [ Example6AutocompleteCellTypeComponent ]})
export class AppModule { }/* end-file */<div> <example6-autocomplete-cell-type></example6-autocomplete-cell-type></div>The filteringCaseSensitive option
By default, the autocomplete search is case-insensitive — typing "bl" matches both "Black" and "blue". Set filteringCaseSensitive: true to require an exact case match when filtering suggestions.
The left column uses the default case-insensitive behavior. The right column has filteringCaseSensitive: true — only options whose case matches the typed characters are shown.
/* file: app.component.ts */import { Component } from '@angular/core';import { GridSettings } from '@handsontable/angular-wrapper';
@Component({ selector: 'example7-autocomplete-cell-type', standalone: false, template: ` <div> <hot-table [data]="data" [settings]="gridSettings"></hot-table> </div>`})export class Example7AutocompleteCellTypeComponent { readonly colors = [ 'Black', 'Blue', 'brown', 'cyan', 'Gray', 'green', 'Lime', 'Magenta', 'Navy', 'olive', 'orange', 'Pink', 'Purple', 'Red', 'silver', 'Teal', 'White', 'Yellow', ];
readonly data = [ ['Black', 'Black'], ['Blue', 'Blue'], ['Gray', 'Gray'], ['Red', 'Red'], ['White', 'White'], ];
readonly gridSettings: GridSettings = { height: 'auto', autoWrapRow: true, autoWrapCol: true, colHeaders: ['Case-insensitive (default)', 'Case-sensitive'], columns: [ { type: 'autocomplete', source: this.colors, strict: false, }, { type: 'autocomplete', source: this.colors, strict: false, // match case while searching autocomplete options filteringCaseSensitive: true, }, ], };}/* end-file */
/* file: app.module.ts */import { NgModule, ApplicationConfig } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { registerAllModules } from 'handsontable/registry';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, HotTableModule } from '@handsontable/angular-wrapper';import { CommonModule } from '@angular/common';import { NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';/* start:skip-in-compilation */import { Example7AutocompleteCellTypeComponent } from './app.component';/* end:skip-in-compilation */
// register Handsontable's modulesregisterAllModules();
export const appConfig: ApplicationConfig = { providers: [ { provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE, } as HotGlobalConfig } ],};
@NgModule({ imports: [ BrowserModule, HotTableModule, CommonModule ], declarations: [ Example7AutocompleteCellTypeComponent ], providers: [...appConfig.providers], bootstrap: [ Example7AutocompleteCellTypeComponent ]})
export class AppModule { }/* end-file */<div> <example7-autocomplete-cell-type></example7-autocomplete-cell-type></div>Related articles
Related guides
Configuration options
Core methods
Hooks