or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cell-types-editing.mdcore-operations.mddata-grid-features.mdevent-system.mdhelper-utilities.mdindex.mdinternationalization.mdplugin-system.mdui-interaction.md
tile.json

event-system.mddocs/

Event System (Hooks)

Comprehensive event system with 200+ hooks for lifecycle management, data changes, user interactions, and customization. The hook system enables deep integration and custom behaviors without modifying core code.

Capabilities

Hook Management System

Core system for registering, managing, and executing event hooks.

/**
 * Hook management interface
 */
interface Hooks {
  /** Add hook callback with optional context */
  add(key: string, callback: Function, context?: object): void;
  
  /** Add hook callback that executes only once */
  once(key: string, callback: Function, context?: object): void;
  
  /** Remove specific hook callback */
  remove(key: string, callback: Function): void;
  
  /** Execute all callbacks for a hook */
  run(key: string, ...args: any[]): any;
  
  /** Check if hook has any callbacks */
  has(key: string): boolean;
  
  /** Check if specific callback is registered */
  isRegistered(key: string, callback: Function): boolean;
  
  /** Get all registered callbacks for a hook */
  getRegistered(key: string): Function[];
  
  /** Destroy all hooks and callbacks */
  destroy(): void;
}

// Access hooks via instance
const hooks = hot.getHooks();
hooks.add('afterChange', (changes, source) => {
  console.log('Data changed:', changes);
});

Usage Examples:

// Add hook with context
hot.addHook('afterSelection', function(row, col) {
  console.log('Selected cell:', row, col);
}, this);

// Remove specific hook
const callback = (changes) => console.log(changes);
hot.addHook('afterChange', callback);
hot.removeHook('afterChange', callback);

// One-time hook execution
hot.addHookOnce('afterInit', () => {
  console.log('Grid initialized');
});

Hook Categories

Lifecycle Hooks

Core application lifecycle events.

// Initialization hooks
type InitHooks = 
  | 'beforeInit'     // Before grid initialization
  | 'afterInit'      // After grid initialization
  | 'afterDestroy'   // After grid destruction
  ;

// Rendering hooks  
type RenderHooks =
  | 'beforeRender'         // Before grid rendering
  | 'afterRender'          // After grid rendering
  | 'beforeRefreshDimensions' // Before dimension calculation
  | 'afterRefreshDimensions'  // After dimension calculation
  ;

// Settings hooks
type SettingsHooks =
  | 'beforeUpdateSettings' // Before settings update
  | 'afterUpdateSettings'  // After settings update
  | 'afterCellMetaReset'   // After cell meta reset
  ;

Data Manipulation Hooks

Events related to data changes and validation.

// Data change hooks
type DataHooks =
  | 'beforeChange'      // Before data change (preventable)
  | 'afterChange'       // After data change
  | 'beforeLoadData'    // Before loading new data
  | 'afterLoadData'     // After loading new data
  | 'beforeSetRangeStartOnly' // Before setting range start
  | 'beforeSetRangeStart'     // Before setting range start
  | 'beforeSetRangeEnd'       // Before setting range end
  ;

// Validation hooks
type ValidationHooks =
  | 'beforeValidate'    // Before cell validation
  | 'afterValidate'     // After cell validation
  | 'beforeGetCellMeta' // Before getting cell metadata
  | 'afterGetCellMeta'  // After getting cell metadata
  ;

Usage Examples:

// Prevent certain changes
hot.addHook('beforeChange', (changes, source) => {
  for (let i = changes.length - 1; i >= 0; i--) {
    const [row, prop, oldValue, newValue] = changes[i];
    if (prop === 'readOnly' && newValue === 'admin') {
      changes.splice(i, 1); // Remove change
    }
  }
});

// React to data changes
hot.addHook('afterChange', (changes, source) => {
  if (source === 'edit') {
    // Save changes to server
    saveData(changes);
  }
});

Selection and Navigation Hooks

Events for cell/range selection and keyboard navigation.

// Selection hooks
type SelectionHooks =
  | 'beforeSelection'        // Before selection change (preventable)
  | 'afterSelection'         // After selection change
  | 'beforeSelectionFocusSet' // Before focus on selection
  | 'afterSelectionFocusSet'  // After focus on selection
  | 'beforeSelectionByProp'   // Before selection by property
  | 'afterSelectionByProp'    // After selection by property
  | 'beforeDeselect'          // Before deselection
  | 'afterDeselect'           // After deselection
  ;

// Navigation hooks
type NavigationHooks =
  | 'beforeKeyDown'      // Before key press (preventable)
  | 'afterKeyDown'       // After key press
  | 'beforeOnCellMouseDown' // Before cell mouse down
  | 'afterOnCellMouseDown'  // After cell mouse down
  | 'beforeOnCellMouseOver' // Before cell mouse over
  | 'afterOnCellMouseOver'  // After cell mouse over
  ;

Usage Examples:

// Custom navigation behavior
hot.addHook('beforeKeyDown', (event) => {
  if (event.keyCode === 13) { // Enter key
    // Custom enter behavior
    event.stopImmediatePropagation();
    return false;
  }
});

// Track selection changes
hot.addHook('afterSelection', (row, col, row2, col2, preventScrolling, selectionLayerLevel) => {
  console.log(`Selected range: ${row},${col} to ${row2},${col2}`);
});

Row and Column Hooks

Events for row/column manipulation operations.

// Row hooks
type RowHooks =
  | 'beforeCreateRow'    // Before row creation (preventable)
  | 'afterCreateRow'     // After row creation
  | 'beforeRemoveRow'    // Before row removal (preventable) 
  | 'afterRemoveRow'     // After row removal
  | 'beforeRowMove'      // Before row move (preventable)
  | 'afterRowMove'       // After row move
  | 'beforeRowResize'    // Before row resize
  | 'afterRowResize'     // After row resize
  ;

// Column hooks
type ColumnHooks =
  | 'beforeCreateCol'    // Before column creation (preventable)
  | 'afterCreateCol'     // After column creation
  | 'beforeRemoveCol'    // Before column removal (preventable)
  | 'afterRemoveCol'     // After column removal
  | 'beforeColumnMove'   // Before column move (preventable)
  | 'afterColumnMove'    // After column move
  | 'beforeColumnResize' // Before column resize
  | 'afterColumnResize'  // After column resize
  ;

Plugin-Specific Hooks

Events triggered by specific plugins.

// Sorting hooks
type SortingHooks =
  | 'beforeColumnSort'  // Before column sort (preventable)
  | 'afterColumnSort'   // After column sort
  ;

// Filtering hooks  
type FilteringHooks =
  | 'beforeFilter'      // Before filter application (preventable)
  | 'afterFilter'       // After filter application
  ;

// Copy/Paste hooks
type CopyPasteHooks =
  | 'beforeCopy'        // Before copy operation (preventable)
  | 'afterCopy'         // After copy operation
  | 'beforeCut'         // Before cut operation (preventable)
  | 'afterCut'          // After cut operation
  | 'beforePaste'       // Before paste operation (preventable)
  | 'afterPaste'        // After paste operation
  ;

// Autofill hooks
type AutofillHooks =
  | 'beforeAutofill'            // Before autofill (preventable)
  | 'afterAutofill'             // After autofill
  | 'beforeAutofillInsidePopulate' // Before autofill populate
  | 'afterAutofillInsidePopulate'  // After autofill populate
  ;

Modify Hooks

Special hooks that allow data transformation during processing.

// Data modification hooks
type ModifyHooks =
  | 'modifyData'           // Modify source data
  | 'modifyRowData'        // Modify row data
  | 'modifyColWidth'       // Modify column width
  | 'modifyRowHeight'      // Modify row height
  | 'modifyColHeader'      // Modify column header
  | 'modifyRowHeader'      // Modify row header
  | 'modifyAutofillRange'  // Modify autofill range
  | 'modifyFocusedElement' // Modify focused element
  | 'modifyGetCellCoords'  // Modify cell coordinates
  ;

Usage Examples:

// Transform data during rendering
hot.addHook('modifyData', (row, col, valueHolder, ioMode) => {
  if (ioMode === 'get' && col === 2) {
    // Format currency column
    valueHolder.value = '$' + valueHolder.value;
  }
});

// Adjust column widths dynamically
hot.addHook('modifyColWidth', (width, col) => {
  if (col === 0) {
    return Math.max(width, 100); // Minimum width
  }
  return width;
});

Hook Parameters and Return Values

Common Hook Patterns

// Before hooks (preventable) - return false to prevent
hot.addHook('beforeChange', (changes, source) => {
  // Validate changes
  if (invalidChanges(changes)) {
    return false; // Prevent the change
  }
});

// After hooks - no return value expected
hot.addHook('afterChange', (changes, source) => {
  // React to changes
  updateUI(changes);
});

// Modify hooks - return modified value
hot.addHook('modifyColWidth', (width, col) => {
  return col === 0 ? 150 : width; // Set first column width
});

Hook Parameter Types

// Common parameter interfaces
interface HookChangeData {
  changes: CellChange[];        // Array of [row, prop, oldVal, newVal]
  source: ChangeSource;         // Source of change ('edit', 'paste', etc.)
}

interface HookSelectionData {
  row: number;                  // Start row
  col: number;                  // Start column  
  row2: number;                 // End row
  col2: number;                 // End column
  preventScrolling?: boolean;   // Prevent auto-scroll
  selectionLayerLevel?: number; // Selection layer
}

interface HookMoveData {
  rows: number[];              // Array of moved row indices
  target: number;              // Target position
}

Advanced Hook Usage

Conditional Hook Registration

// Add hooks based on conditions
if (hot.getSettings().enableAudit) {
  hot.addHook('afterChange', auditChanges);
  hot.addHook('afterSelection', logSelection);
}

// Plugin-specific hooks
hot.addHook('afterPluginsInitialized', () => {
  const sortPlugin = hot.getPlugin('ColumnSorting');
  if (sortPlugin.isEnabled()) {
    hot.addHook('afterColumnSort', handleSort);
  }
});

Hook Priority and Execution Order

// Hooks execute in registration order
hot.addHook('afterChange', firstHandler);   // Executes first
hot.addHook('afterChange', secondHandler);  // Executes second

// Use once() for initialization tasks
hot.addHookOnce('afterInit', () => {
  console.log('Grid ready - this runs only once');
});

This comprehensive hook system provides complete control over Handsontable's behavior, enabling complex customizations while maintaining clean separation of concerns.