CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-handsontable

JavaScript data grid component with spreadsheet-like functionality for React, Angular and Vue applications

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

ui-interaction.mddocs/

UI and Interaction

User interface components and interaction features including context menus, selection handling, accessibility, and visual customization.

Capabilities

Context Menus

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';

Selection Management

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 Navigation and Shortcuts

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';
}

Custom Borders

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 and Mobile Support

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;
}

Accessibility Features

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;
}

Visual Customization

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 });
});

docs

cell-types-editing.md

core-operations.md

data-grid-features.md

event-system.md

helper-utilities.md

index.md

internationalization.md

plugin-system.md

ui-interaction.md

tile.json