The BaseEditorComponent class provides a foundation for creating React-based custom cell editors that integrate seamlessly with Handsontable's editing lifecycle. It implements the full Handsontable editor interface while allowing React component patterns.
Base class for creating custom React-based cell editors with full Handsontable editor lifecycle integration.
/**
* Base class for React-based Handsontable editors
* Implements the complete BaseEditor interface with React component lifecycle
*/
class BaseEditorComponent<P = {}, S = {}, SS = any>
extends React.Component<P & BaseEditorProps, S, SS>
implements Handsontable.editors.BaseEditor;
interface BaseEditorProps extends HotEditorProps {
/** Editor scope identifier - column index or 'global' */
editorColumnScope?: EditorScopeIdentifier;
/** Callback to emit editor instance to parent */
emitEditorInstance?: (editor: BaseEditorComponent, column: EditorScopeIdentifier) => void;
}
interface HotEditorProps {
/** Editor marker property */
"hot-editor": any;
/** Editor DOM element ID */
id?: string;
/** CSS class name */
className?: string;
/** Inline styles */
style?: React.CSSProperties;
}
type EditorScopeIdentifier = 'global' | number;Usage Examples:
import React, { Component } from 'react';
import { BaseEditorComponent } from '@handsontable/react';
// Simple text editor with validation
class CustomTextEditor extends BaseEditorComponent {
constructor(props) {
super(props);
this.state = {
value: ''
};
}
componentDidMount() {
super.componentDidMount();
this.setState({ value: this.originalValue || '' });
}
handleChange = (event) => {
this.setState({ value: event.target.value });
};
handleKeyDown = (event) => {
if (event.key === 'Enter') {
this.finishEditing();
} else if (event.key === 'Escape') {
this.cancelChanges();
}
};
getValue() {
return this.state.value;
}
setValue(value) {
this.setState({ value: value || '' });
}
render() {
return (
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
onKeyDown={this.handleKeyDown}
autoFocus
style={{ width: '100%', border: 'none', outline: 'none' }}
/>
);
}
}
// Dropdown editor with custom options
class CustomDropdownEditor extends BaseEditorComponent {
constructor(props) {
super(props);
this.state = {
value: '',
options: ['Option 1', 'Option 2', 'Option 3']
};
}
componentDidMount() {
super.componentDidMount();
this.setState({ value: this.originalValue || '' });
}
handleChange = (event) => {
this.setState({ value: event.target.value });
this.finishEditing();
};
getValue() {
return this.state.value;
}
setValue(value) {
this.setState({ value: value || '' });
}
render() {
return (
<select
value={this.state.value}
onChange={this.handleChange}
autoFocus
style={{ width: '100%', border: 'none' }}
>
<option value="">Select...</option>
{this.state.options.map(option => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
);
}
}
// Usage in HotTable
function TableWithCustomEditor() {
return (
<HotTable
data={[['Sample', 'Data']]}
colHeaders={true}
licenseKey="non-commercial-and-evaluation"
>
<HotColumn data={0}>
<CustomTextEditor hot-editor />
</HotColumn>
<HotColumn data={1}>
<CustomDropdownEditor hot-editor />
</HotColumn>
</HotTable>
);
}Properties available on BaseEditorComponent instances during the editing lifecycle:
/** Handsontable instance reference */
hotInstance: Handsontable | null;
/** Current row index being edited */
row: number | null;
/** Current column index being edited */
col: number | null;
/** Property name or column identifier */
prop: string | number | null;
/** Cell DOM element being edited */
TD: HTMLTableCellElement | null;
/** Original cell value before editing */
originalValue: any;
/** Cell properties object with metadata */
cellProperties: Handsontable.CellProperties | null;
/** Editor state (inherited from BaseEditor) */
state: any;
/** Reference to custom editor instance wrapper */
hotCustomEditorInstance: any;Methods inherited from Handsontable.editors.BaseEditor that handle the editing lifecycle:
/**
* Prepare the editor for editing a specific cell
* @param row - Row index
* @param col - Column index
* @param prop - Property name
* @param TD - Cell DOM element
* @param originalValue - Current cell value
* @param cellProperties - Cell metadata
*/
prepare(
row: number,
col: number,
prop: string | number,
TD: HTMLTableCellElement,
originalValue: any,
cellProperties: Handsontable.CellProperties
): any;
/**
* Initialize the editor (called once)
*/
init(...args: any[]): any;
/**
* Open the editor for editing
*/
open(...args: any[]): any;
/**
* Close the editor
*/
close(...args: any[]): any;
/**
* Focus the editor input
*/
focus(...args: any[]): any;
/**
* Get the current editor value
* @returns Current editor value
*/
getValue(...args: any[]): any;
/**
* Set the editor value
* @param value - Value to set
*/
setValue(...args: any[]): any;
/**
* Begin the editing process
*/
beginEditing(...args: any[]): any;
/**
* Finish editing and save the value
*/
finishEditing(...args: any[]): any;
/**
* Cancel editing and revert changes
*/
cancelChanges(...args: any[]): any;
/**
* Save the current editor value to the cell
*/
saveValue(...args: any[]): any;
/**
* Discard the editor without saving
*/
discardEditor(...args: any[]): any;
/**
* Enable full edit mode
*/
enableFullEditMode(...args: any[]): any;
/**
* Check if editor is in full edit mode
* @returns True if in full edit mode
*/
isInFullEditMode(...args: any[]): boolean;
/**
* Check if editor is open
* @returns True if editor is open
*/
isOpened(...args: any[]): boolean;
/**
* Check if editor is waiting
* @returns True if editor is waiting
*/
isWaiting(...args: any[]): boolean;Methods for managing Handsontable hooks within custom editors:
/**
* Add a hook callback
* @param key - Hook name
* @param callback - Hook callback function
*/
addHook(...args: any[]): any;
/**
* Remove hooks by key
* @param key - Hook name to remove
*/
removeHooksByKey(...args: any[]): any;
/**
* Clear all hooks
*/
clearHooks(...args: any[]): any;Methods for getting information about the cell being edited:
/**
* Get the edited cell element
* @returns Cell DOM element
*/
getEditedCell(...args: any[]): HTMLTableCellElement;
/**
* Get the edited cell rectangle
* @returns Cell bounding rectangle
*/
getEditedCellRect(...args: any[]): DOMRect;
/**
* Get the edited cell's z-index
* @returns Z-index value
*/
getEditedCellsZIndex(...args: any[]): number;To use custom editors, they must be provided as children of HotColumn or HotTable components:
// Column-specific editor
<HotColumn data="description">
<CustomEditor hot-editor />
</HotColumn>
// Global editor for entire table
<HotTable data={data}>
<CustomEditor hot-editor />
<HotColumn data={0} />
<HotColumn data={1} />
</HotTable>The
hot-editorEditors can be scoped to specific columns or applied globally:
The
editorColumnScope