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 — all in under 5KB gzipped.
What is duck-vim?
duck-vim is a keyboard shortcut engine for the browser. It gives you a registry-based system where shortcuts are declared, not hardcoded. Keybindings can be discovered (via command palettes), customized (per user), and composed (multi-key sequences like g then d) without touching component code.
The core is plain DOM with zero dependencies. React bindings are provided as an optional layer on top.
Why duck-vim?
Most keyboard shortcut libraries solve the simple case (bind Ctrl+K to a function) but fall apart when you need:
- Multi-key sequences like Vim's g+d (press g, then d within a timeout window)
- Prefix awareness so the UI can show "waiting for next key..." states
- 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
duck-vim handles all of these in under 5KB gzipped.
Architecture
duck-vim is organized into independent modules that compose together:
| 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 in 2 minutes
- Core Concepts — Key descriptors, sequences, prefixes, and the Mod key
- API Reference — Full API for every module
- Guides — Recipes for common patterns
- Course — Step-by-step 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)That's it. Press Ctrl+K and the command fires. No React, no framework, no config files.