Engine options
Pass options to createKeybindingEngine() or <KeybindProvider options={…}>.
import { createKeybindingEngine, defaultIgnore } from '@tactile-js/core';
const kb = createKeybindingEngine({ source: undefined, defaultMatch: 'hybrid', sequenceTimeout: 1000, ignore: defaultIgnore, platform: undefined, debug: false,});source?: KeyEventSource
Section titled “source?: KeyEventSource”Where key events come from. Defaults to a DOM source on document.
Override for tests, Electron, or embedded editors:
const kb = createKeybindingEngine({ source: { on(type, listener) { const h = (e: KeyboardEvent) => listener(e); document.addEventListener(type, h); return () => document.removeEventListener(type, h); }, },});The engine calls source.on('keydown', …) and source.on('keyup', …) once at creation. Rules are added/removed from the registry — listeners are not re-bound per rule.
defaultMatch?: MatchMode
Section titled “defaultMatch?: MatchMode”Default match strategy for rules that don’t set their own match. Defaults to 'hybrid'. The full
mode-by-key-type behavior table lives in Match modes.
// Character-based matching for every ruleconst kb = createKeybindingEngine({ defaultMatch: 'logical' });Per-rule override:
kb.add({ id: 'vim.j', keys: 'j', match: 'physical', handler: down });sequenceTimeout?: number
Section titled “sequenceTimeout?: number”Maximum gap in milliseconds between strokes of a multi-key sequence. Defaults to 1000.
kb.add({ id: 'inbox', keys: 'g i', handler: goToInbox });// 'g' then 'i' within 1000msIncrease for slower users or accessibility:
createKeybindingEngine({ sequenceTimeout: 3000 });ignore?: (event: KeyEvent) => boolean
Section titled “ignore?: (event: KeyEvent) => boolean”Predicate returning true when the event should be skipped. Defaults to defaultIgnore, which returns true for:
<input><textarea><select>contenteditableelements
import { createKeybindingEngine, defaultIgnore } from '@tactile-js/core';
// Never ignore — shortcuts fire everywhere (like VS Code's window listener)const kb = createKeybindingEngine({ ignore: () => false });Allow one shortcut in inputs (per-rule)
Section titled “Allow one shortcut in inputs (per-rule)”The common case — a command palette that must open from anywhere, including text fields — doesn’t need a custom predicate. Opt the rule in:
kb.add({ id: 'palette', keys: 'mod+k', enableInFormFields: true, handler: openPalette,});Everything else stays paused while the user types. Two guardrails are built in: sequences never
fire inside form fields (they’re indistinguishable from typing), and debug: true warns if you set
this on a binding without a ctrl/alt/meta modifier, since plain keys would collide with text entry.
Allow shortcuts by predicate (engine-wide)
Section titled “Allow shortcuts by predicate (engine-wide)”For broader policies, replace the predicate:
createKeybindingEngine({ ignore: (event) => { if (!defaultIgnore(event)) return false; // Let mod+s through even in inputs if (event.metaKey && event.code === 'KeyS') return false; return true; },});Monaco / CodeMirror pattern
Section titled “Monaco / CodeMirror pattern”Gate shortcuts with when instead of a global ignore:
kb.add({ id: 'editor.save', keys: 'mod+s', when: 'editorFocus', handler: save,});
// In your editor component on focus/blur:kb.context.set('editorFocus', true);platform?: Platform
Section titled “platform?: Platform”Override platform detection ('mac' | 'other'). Auto-detected from navigator when omitted.
Affects:
modresolution (metavsctrl)format()label output (⌘KvsCtrl+K)
// Force Windows-style labels on any OS (e.g. for screenshots)kb.format('mod+k', 'other'); // 'Ctrl+K'debug?: boolean
Section titled “debug?: boolean”Log registrations, collisions, and dispatches to the console. Defaults to false.
const kb = createKeybindingEngine({ debug: true });// [keybind] registered palette.open (mod+k)// [keybind] collision on "mod+k": a vs b// [keybind] mod+k -> palette.open (won over 1)Useful during development. Disable in production.
Next steps
Section titled “Next steps”- Core API reference — every method on the engine
- Match modes — what
defaultMatchactually controls - Recipes — these options applied to real UI patterns