User interface components and interaction features including context menus, selection handling, accessibility, and visual customization.
Right-click context menu system with predefined and custom menu items.
// Context menu configuration
interface ContextMenuSettings {
enabled?: boolean;
items?: ContextMenuItems;
callback?: (key: string, selection: ContextMenuSelection[], clickEvent: MouseEvent) => void;
}
type ContextMenuItems = Array<
| string // Predefined item key
| ContextMenuItemConfig
| ContextMenuSubmenuConfig
| '-' // Separator
>;
interface ContextMenuItemConfig {
key?: string;
name: string | (() => string);
callback?: (key: string, selection: ContextMenuSelection[], clickEvent: MouseEvent) => void;
disabled?: boolean | (() => boolean);
hidden?: boolean | (() => boolean);
renderer?: (hot: Core, wrapper: HTMLElement, row: number, col: number, prop: string | number, itemValue: string) => HTMLElement;
}
interface ContextMenuSubmenuConfig {
key?: string;
name: string | (() => string);
submenu: {
items: ContextMenuItems;
};
}
interface ContextMenuSelection {
start: CellCoords;
end: CellCoords;
}
// Plugin methods via hot.getPlugin('contextMenu')
class ContextMenu {
/**
* Open context menu at position
* @param event - Mouse event or coordinates
*/
open(event: MouseEvent | { pageX: number; pageY: number }): void;
/**
* Close context menu
*/
close(): void;
/**
* Execute menu command
* @param commandName - Command to execute
*/
executeCommand(commandName: string): void;
/**
* Check if menu is open
* @returns True if menu is open
*/
isOpened(): boolean;
}
// Predefined menu item keys
type PredefinedMenuItemKey =
| 'row_above' | 'row_below' | 'col_left' | 'col_right'
| 'remove_row' | 'remove_col' | 'undo' | 'redo'
| 'make_read_only' | 'alignment' | 'cut' | 'copy'
| 'freeze_column' | 'unfreeze_column' | 'borders'
| 'commentsAddEdit' | 'commentsRemove' | 'mergeCells' | 'add_child'
| 'detach_from_parent' | 'hidden_columns_hide' | 'hidden_columns_show'
| 'hidden_rows_hide' | 'hidden_rows_show' | 'filter_by_condition'
| 'filter_by_condition2' | 'filter_operators' | 'filter_by_value'
| 'filter_action_bar';Advanced selection handling with multiple selection modes and programmatic control.
/**
* Cell coordinates class for position management
*/
class CellCoords {
constructor(row: number, col: number);
row: number;
col: number;
/**
* Check if coordinates are equal
* @param coords - Coordinates to compare
* @returns True if equal
*/
isEqual(coords: CellCoords): boolean;
/**
* Check if this coordinate is southeast of another
* @param coords - Coordinates to compare
* @returns True if southeast
*/
isSouthEastOf(coords: CellCoords): boolean;
/**
* Check if this coordinate is northwest of another
* @param coords - Coordinates to compare
* @returns True if northwest
*/
isNorthWestOf(coords: CellCoords): boolean;
/**
* Clone coordinates
* @returns New CellCoords instance
*/
clone(): CellCoords;
}
/**
* Cell range class for selection management
*/
class CellRange {
constructor(highlight: CellCoords, from: CellCoords, to: CellCoords);
highlight: CellCoords; // Highlighted cell
from: CellCoords; // Top-left corner
to: CellCoords; // Bottom-right corner
/**
* Get all coordinates in the range
* @returns Array of all coordinates
*/
getAll(): CellCoords[];
/**
* Check if range contains coordinates
* @param coords - Coordinates to check
* @returns True if contains
*/
includes(coords: CellCoords): boolean;
/**
* Check if range includes only one cell
* @returns True if single cell
*/
isSingle(): boolean;
/**
* Get top-left corner
* @returns Top-left coordinates
*/
getTopLeftCorner(): CellCoords;
/**
* Get bottom-right corner
* @returns Bottom-right coordinates
*/
getBottomRightCorner(): CellCoords;
/**
* Clone range
* @returns New CellRange instance
*/
clone(): CellRange;
}
// Selection methods on Core instance
interface SelectionMethods {
/**
* Select single cell
* @param row - Row index
* @param col - Column index
* @param scrollToCell - Whether to scroll to cell
* @returns True if successful
*/
selectCell(row: number, col: number, scrollToCell?: boolean): boolean;
/**
* Select multiple cells or ranges
* @param coords - Array of [row, col, endRow, endCol] tuples
* @param scrollToCell - Whether to scroll to selection
* @returns True if successful
*/
selectCells(coords: [number, number, number, number][], scrollToCell?: boolean): boolean;
/**
* Select entire rows
* @param startRow - Starting row
* @param endRow - Ending row (optional)
* @returns True if successful
*/
selectRows(startRow: number, endRow?: number): boolean;
/**
* Select entire columns
* @param startCol - Starting column
* @param endCol - Ending column (optional)
* @returns True if successful
*/
selectColumns(startCol: number, endCol?: number): boolean;
/**
* Select all cells
*/
selectAll(): void;
/**
* Clear selection
*/
deselectCell(): void;
/**
* Get selected ranges
* @returns Array of selected ranges
*/
getSelectedRange(): CellRange[] | undefined;
/**
* Get last selected range
* @returns Last selected range
*/
getSelectedRangeLast(): CellRange | undefined;
}Keyboard interaction system with customizable shortcuts and navigation.
// Keyboard shortcuts via hot.getShortcutManager()
interface ShortcutManager {
/**
* Get context for current selection
* @returns Current context name
*/
getContext(): string;
/**
* Add custom shortcut
* @param keys - Key combination (e.g., 'ctrl+s')
* @param callback - Function to execute
* @param contextName - Context where shortcut is active
*/
addShortcut(keys: string, callback: Function, contextName?: string): void;
/**
* Remove shortcut
* @param keys - Key combination to remove
* @param contextName - Context to remove from
*/
removeShortcut(keys: string, contextName?: string): void;
}
// Default keyboard shortcuts
interface DefaultShortcuts {
'Enter': 'move down';
'Shift+Enter': 'move up';
'Tab': 'move right';
'Shift+Tab': 'move left';
'Arrow keys': 'navigate';
'Ctrl+A': 'select all';
'Ctrl+C': 'copy';
'Ctrl+X': 'cut';
'Ctrl+V': 'paste';
'Ctrl+Z': 'undo';
'Ctrl+Y': 'redo';
'Delete': 'clear cell';
'F2': 'edit cell';
'Escape': 'cancel edit';
}Advanced border styling for cells and ranges.
// Custom borders configuration
interface CustomBordersSettings {
enabled?: boolean;
}
interface BorderOptions {
width?: number;
color?: string;
style?: 'solid' | 'dashed' | 'dotted' | 'double';
}
interface BorderRange {
range: {
from: CellCoords;
to: CellCoords;
};
top?: BorderOptions;
right?: BorderOptions;
bottom?: BorderOptions;
left?: BorderOptions;
}
// Plugin methods via hot.getPlugin('customBorders')
class CustomBorders {
/**
* Set borders for range
* @param range - Cell range
* @param borderOptions - Border styling options
*/
setBorders(range: CellRange | [number, number, number, number], borderOptions: {
top?: BorderOptions;
right?: BorderOptions;
bottom?: BorderOptions;
left?: BorderOptions;
}): void;
/**
* Get borders for cell
* @param row - Row index
* @param col - Column index
* @returns Border options
*/
getBorders(row: number, col: number): BorderOptions | undefined;
/**
* Clear borders from range
* @param range - Cell range to clear
*/
clearBorders(range: CellRange | [number, number, number, number]): void;
}Touch interaction support for mobile devices.
// Touch scroll configuration
interface TouchScrollSettings {
enabled?: boolean;
}
// Touch scroll plugin methods via hot.getPlugin('touchScroll')
class TouchScroll {
/**
* Check if touch scrolling is enabled
* @returns True if enabled
*/
isEnabled(): boolean;
/**
* Enable touch scrolling
*/
enablePlugin(): void;
/**
* Disable touch scrolling
*/
disablePlugin(): void;
}Built-in accessibility support for screen readers and keyboard navigation.
// Accessibility configuration (automatically enabled)
interface AccessibilityFeatures {
// ARIA attributes automatically applied
'aria-label': 'Data grid';
'aria-rowcount': number;
'aria-colcount': number;
'role': 'grid';
// Keyboard navigation support
tabIndex: number;
// Screen reader announcements
announceSelectionChanges: boolean;
announceDataChanges: boolean;
}
// Focus management methods
interface FocusManager {
/**
* Set focus on specific cell
* @param coords - Cell coordinates
*/
setFocus(coords: CellCoords): void;
/**
* Get currently focused cell
* @returns Focused cell coordinates
*/
getFocusedCell(): CellCoords | null;
/**
* Check if grid has focus
* @returns True if focused
*/
isFocused(): boolean;
}Styling and theming options for grid appearance.
// CSS class configuration
interface StyleConfiguration {
className?: string; // Main container class
currentRowClassName?: string; // Active row highlight
currentColClassName?: string; // Active column highlight
currentHeaderClassName?: string; // Active header highlight
activeHeaderClassName?: string; // Selected header class
invalidCellClassName?: string; // Invalid cell styling
readOnlyCellClassName?: string; // Read-only cell styling
commentedCellClassName?: string; // Commented cell styling
noWordWrapClassName?: string; // No text wrap class
// Table styling
tableClassName?: string; // Table element class
stretchH?: 'none' | 'last' | 'all'; // Column stretching
// Cell styling
cells?: (row: number, col: number) => {
className?: string;
readOnly?: boolean;
type?: string;
[key: string]: any;
};
}Usage Examples:
// Context menu with custom items
const hot = new Handsontable(container, {
data: myData,
contextMenu: {
items: {
'row_above': {},
'row_below': {},
'separator': '-',
'custom_item': {
name: 'Custom Action',
callback: (key, selection, clickEvent) => {
console.log('Custom action executed', selection);
}
}
}
}
});
// Custom keyboard shortcuts
const shortcutManager = hot.getShortcutManager();
shortcutManager.addShortcut('ctrl+shift+s', () => {
console.log('Custom save shortcut');
});
// Custom borders
const customBorders = hot.getPlugin('customBorders');
customBorders.setBorders([0, 0, 2, 2], {
top: { width: 3, color: '#ff0000', style: 'solid' },
bottom: { width: 3, color: '#ff0000', style: 'solid' }
});
// Selection events
hot.addHook('afterSelection', (row, col, row2, col2) => {
console.log('Selection changed:', { row, col, row2, col2 });
});
hot.addHook('afterSelectionEnd', (row, col, row2, col2) => {
console.log('Selection ended:', { row, col, row2, col2 });
});