Handsontable Editor Development
SkillDev toolsUse when creating or modifying a Handsontable cell editor - covers the editor lifecycle state machine (VIRGIN/EDITING/WAITING/FINISHED), DOM management, focus handling, positioning with getEditedCellRect, and validation integration
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Handsontable Editor Development skill
What this skill tells your AI
The instructions your AI receives, as published by handsontable/handsontable in .claude/skills/handsontable-editor-dev/SKILL.md and read by ahel’s review.
Editor state machine
Editors are stateful objects cycling through four states: VIRGIN (just created, never opened), EDITING (visible and accepting input), WAITING (editing finished, awaiting async validation), and FINISHED (validation complete, editor closed). Never skip states or transition backwards except through a full reset.
File structure
src/editors/{editorName}/
{editorName}.ts # Main class extending BaseEditor
index.ts # Re-exports
Registry: src/editors/registry.ts. Factory: src/editors/factory.ts.
Lifecycle methods (required overrides)
| Method | Purpose |
|---|---|
init() | Create DOM elements, set up event listeners. |
prepare() | Called before editing starts. Receives row, col, prop, TD, cellProperties. |
getValue() | Return the current editor value. |
setValue(newValue) | Set the editor value (called before open). |
open() | Show the editor, position it, capture focus. |
close() | Hide the editor, release focus. |
focus() | Set focus to the editor's input element. |
beginEditing() | Start the editing process (calls prepare, setValue, open). |
finishEditing() | End editing, trigger validation, close if valid. |
Positioning
Always use getEditedCellRect() for viewport-, scroll-, and overlay-aware positioning. Never calculate position manually - it will break with frozen rows/columns and scrolled viewports.
Key patterns
- All editors extend
BaseEditorfromsrc/editors/baseEditor/baseEditor.ts. - Support both full edit mode (Enter key opens editor, all keys go to the editor) and fast edit mode (typing a character immediately opens the editor with that character).
finishEditing()supports async validation - the editor enters WAITING state until the validator resolves.- Use
this.hot.rootDocumentinstead ofdocumentfor DOM creation (required for iframe support). - Use
EventManagerfor event handling so listeners are cleaned up automatically.
Reference implementations
src/editors/textEditor/textEditor.ts- Standard text editing with a textarea.src/editors/selectEditor/selectEditor.ts- Dropdown selection pattern.src/editors/baseEditor/baseEditor.ts- Base class defining all lifecycle methods and state transitions.
IME (Input Method Editor) gotcha
For CJK languages, compositionstart/compositionend events have timing issues that affect when to read the editor value. Do not read or commit the value between compositionstart and compositionend - the composition is still in progress and the value is intermediate. The BaseEditor handles this, but custom editors that override key event handling must respect composition state.
Common mistakes
- Forgetting to clean up DOM elements and event listeners in
close(). - Not handling focus correctly, which breaks keyboard navigation after closing the editor.
- Positioning without
getEditedCellRect(), which breaks with overlays, scroll, and frozen rows/columns. - Not supporting both LTR and RTL layouts - always use logical CSS properties or check
this.hot.isRtl(). - Using
documentdirectly instead ofthis.hot.rootDocument. - Not calling
supermethods in lifecycle overrides (super.init(),super.close(), etc.).
Signals
- GitHub stars
- 22k
- Forks
- 3k
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
handsontable-editor-dev- Source
- github.com/handsontable/handsontable