Skip to main content

Lesson 1: Introduction

Why keyboard shortcuts matter and how duck-vim approaches the problem.

Why keyboard shortcuts?

Keyboard shortcuts aren't only for power users. They serve three audiences:

Power users want to stay on the keyboard. Reaching for the mouse breaks flow. VS Code, Figma, and Notion ship deep keyboard interfaces for this reason.

Accessibility depends on keyboard navigation. Users who can't use a mouse rely on shortcuts. WCAG 2.1 guideline 2.1 requires all functionality to be operable through a keyboard.

Efficiency is measurable. Studies show keyboard shortcuts cut task completion time by 30-50% for repetitive operations.


The problem with naive approaches

Most developers start with something like this:

// Don't do this
document.addEventListener('keydown', (e) => {
  if (e.ctrlKey && e.key === 'k') {
    openPalette()
  }
  if (e.ctrlKey && e.key === 's') {
    e.preventDefault()
    save()
  }
  // ... 50 more if-statements
})
// Don't do this
document.addEventListener('keydown', (e) => {
  if (e.ctrlKey && e.key === 'k') {
    openPalette()
  }
  if (e.ctrlKey && e.key === 's') {
    e.preventDefault()
    save()
  }
  // ... 50 more if-statements
})

How duck-vim solves this

duck-vim uses a registry pattern. Instead of imperative event handlers, you declare bindings:

registry.register('ctrl+k', {
  name: 'Open Palette',
  execute: () => openPalette(),
})
registry.register('ctrl+k', {
  name: 'Open Palette',
  execute: () => openPalette(),
})

Architecture at a glance

duck-vim is split into small, focused modules:

@gentleduck/vim
├── platform/   -> OS detection, Mod key resolution
├── parser/     -> Parse "ctrl+shift+s" into structured data
├── matcher/    -> Does this KeyboardEvent match this binding?
├── command/    -> Registry + KeyHandler (the core system)
├── sequence/   -> Multi-step sequence matching
├── recorder/   -> Record key combos for settings UIs
├── format/     -> Format bindings for display ("Cmd+S")
└── react/      -> Provider + hooks
@gentleduck/vim
├── platform/   -> OS detection, Mod key resolution
├── parser/     -> Parse "ctrl+shift+s" into structured data
├── matcher/    -> Does this KeyboardEvent match this binding?
├── command/    -> Registry + KeyHandler (the core system)
├── sequence/   -> Multi-step sequence matching
├── recorder/   -> Record key combos for settings UIs
├── format/     -> Format bindings for display ("Cmd+S")
└── react/      -> Provider + hooks

What we'll build in this course

  1. Register and manage keyboard shortcuts in any JavaScript application.
  2. Build multi-key Vim-style sequences.
  3. Integrate shortcuts into React with providers and hooks.
  4. Display shortcuts with platform-aware formatting.
  5. Build a key recorder for shortcut customization UIs.
  6. Build a command palette powered by the registry.
  7. Handle edge cases: scoped bindings, conflict detection, input elements.