CodeMirror Vim mode: put modal editing ahead of ordinary shortcuts

For CodeMirror 6, add vim() from @replit/codemirror-vim before the other keymaps in the extension list. Keep the ordinary editing setup for Insert mode. This package supplies Vim-style modal editing inside CodeMirror; it does not embed a terminal or run your local Vim configuration. The package's own usage example shows this ordering.

In a source-review tool, a developer may want dd to remove a line in Normal mode while typing those same letters literally in Insert mode. A global keydown listener cannot make that distinction reliably for the embedded editor. Let the Vim extension interpret modes, then keep the application's save operation separate.

Enable the CodeMirror 6 package

In an existing bundled application with compatible CodeMirror dependencies:

import { EditorView, basicSetup } from 'codemirror';
import { vim } from '@replit/codemirror-vim';

const view = new EditorView({
  parent: document.querySelector('#source'),
  doc: 'draft line\nkeep this line\n',
  extensions: [vim(), basicSetup]
});

Give #source a visible place in the page and retain any required language extension. The package is specifically the CodeMirror 6 adapter; an older keyMap: 'vim' configuration from CodeMirror 5 is a different integration. Check the imported package and API before debugging key behavior.

The example retains basicSetup, including selection drawing. If your application builds a smaller setup, include drawSelection() from @codemirror/view so Visual mode has the selection rendering the package expects. Do not remove unrelated editing support simply to make a single shortcut work.

Read the mode before interpreting a keystroke

Focus the editor. In Normal mode, press i, type Revised , and press Escape. The document should begin Revised draft line, with the cursor back in Normal mode. Next use dd to delete the current line. Its disappearance is the intended modal action, not two missing typed letters.

If the letters appear in the document instead, inspect whether the editor is still in Insert mode and whether another keymap ran first. The CodeMirror keymap guide explains precedence for ordinary bindings. Vim adds a mode interpreter, so avoid defining broad page-level shortcuts that consume its input before the focused editor receives it.

Keep application buttons for important tasks such as Save and Preview. Someone using a touch screen or unfamiliar with modal editing should still be able to finish the document without discovering a command sequence.

Make optional mappings a deliberate application choice

The adapter exposes the shared Vim configuration API. For example:

import { Vim } from '@replit/codemirror-vim';

Vim.map('jj', '<Esc>', 'insert');
// Remove the application mapping when it is no longer wanted:
// Vim.unmap('jj', 'insert');

This changes how the jj sequence behaves in Insert mode. It can interfere with literal text that contains the same sequence, so make the choice visible to the people who use the editor. Register such configuration once under a clear owner instead of repeating it on every component render. Do not assume a mapping is private to one document merely because one component installed it.

The package also supports defining Ex commands. A command named write still needs your application's actual persistence implementation; its name alone does not save a file. Keep success and failure reporting tied to the completed save request.

Finish with text and focus checks

Read view.state.doc.toString() after the modal sequence. Confirm that entering Insert mode changed the intended text, Escape stopped insertion, and the Normal-mode deletion removed exactly one line. Move focus to an ordinary input outside the editor and type there too; it should retain its normal browser behavior.

Then save the reviewed source through the application's usual handler and reopen it. Modal editing is useful when the saved text matches the developer's edits and the surrounding page remains usable. It is not a substitute for language support, validation, or a successful save.

Keep reading