duck vim
Tiny, framework-agnostic keyboard command engine with optional React bindings.
duck-vim is a keyboard shortcut engine for the browser. Registry-based commands, multi-key sequences, cross-platform Mod key, key recording, and display formatting. Under 5 KB gzipped.
What is duck-vim?
duck-vim is a keyboard shortcut engine for the browser. Shortcuts are declared in a registry rather than hardcoded in event handlers. That makes them discoverable through command palettes, customizable per user, and composable into multi-key sequences like g then d.
The core is plain DOM with zero dependencies. React bindings sit on top as an optional layer.
Why duck-vim?
Most keyboard shortcut libraries cover Ctrl+K to a function and stop. duck-vim also handles:
- Multi-key sequences like Vim's g+d (press g, then d within a timeout).
- Prefix awareness so the UI can show a "waiting for next key..." state.
- Cross-platform Mod key that resolves to Cmd on Mac and Ctrl elsewhere.
- Scoped bindings attached to specific DOM elements, not just
document. - A key recorder for settings UIs where users define their own shortcuts.
- Display formatting that renders
Mod+Shift+Sas Cmd+Shift+S on Mac and Ctrl+Shift+S on Windows.
All of the above fit under 5 KB gzipped.
Architecture
duck-vim is organized into independent modules:
| Module | Purpose | Framework dependency |
|---|---|---|
platform | OS detection, Mod key resolution | None |
parser | Parse and validate key binding strings | None |
matcher | Match keyboard events against parsed bindings | None |
command | Registry + KeyHandler for managing shortcuts | None |
sequence | Multi-step sequence manager | None |
recorder | Record key combinations for settings UIs | None |
format | Format bindings for display (Cmd+S, Ctrl+S) | None |
react | Provider, hooks, and context for React apps | React |
Every module except react is pure DOM. You can use any subset.
Quick links
- Getting Started - Install and run your first shortcut.
- Core Concepts - Key descriptors, sequences, prefixes, the Mod key.
- API Reference - Full API for every module.
- Guides - Recipes for common patterns.
- Course - Tutorial from zero to advanced.
Installation
npm install @gentleduck/vim
npm install @gentleduck/vim
// Core (framework-agnostic)
import { Registry, KeyHandler } from '@gentleduck/vim/command'
import { parseKeyBind } from '@gentleduck/vim/parser'
import { formatForDisplay } from '@gentleduck/vim/format'
// React bindings
import { KeyProvider, useKeyBind, useKeySequence } from '@gentleduck/vim/react'// Core (framework-agnostic)
import { Registry, KeyHandler } from '@gentleduck/vim/command'
import { parseKeyBind } from '@gentleduck/vim/parser'
import { formatForDisplay } from '@gentleduck/vim/format'
// React bindings
import { KeyProvider, useKeyBind, useKeySequence } from '@gentleduck/vim/react'Minimal example
import { Registry, KeyHandler } from '@gentleduck/vim/command'
const registry = new Registry()
const handler = new KeyHandler(registry)
registry.register('ctrl+k', {
name: 'Open Palette',
execute: () => document.getElementById('palette')?.focus(),
})
handler.attach(document)import { Registry, KeyHandler } from '@gentleduck/vim/command'
const registry = new Registry()
const handler = new KeyHandler(registry)
registry.register('ctrl+k', {
name: 'Open Palette',
execute: () => document.getElementById('palette')?.focus(),
})
handler.attach(document)Press Ctrl+K and the command fires. No React, no framework, no config files.