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

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