Skip to main content

Basic setup

Follow these steps to create a working CodeMirror editor with Vim keybindings.
1

Import required packages

Import the Vim extension and CodeMirror core packages:
import { basicSetup, EditorView } from 'codemirror';
import { vim } from "@replit/codemirror-vim";
2

Create the editor

Initialize a new EditorView with the Vim extension:
let view = new EditorView({
  doc: "",
  extensions: [
    // make sure vim is included before other keymaps
    vim(), 
    // include the default keymap and all other keymaps you want to use in insert mode
    basicSetup, 
  ],
  parent: document.querySelector('#editor'),
})
The vim() extension must be included before other keymaps in the extensions array. This ensures Vim keybindings take precedence in normal mode while allowing other keymaps to function properly in insert mode.
3

Add an editor container to your HTML

Create a DOM element where the editor will be mounted:
<div id="editor"></div>
4

Test Vim functionality

Open your application and verify Vim keybindings are working:
  • Press i to enter insert mode
  • Type some text
  • Press Esc to return to normal mode
  • Use h, j, k, l to navigate
  • Try other Vim commands like dd, yy, p, etc.

Complete example

Here’s a full working example you can copy and paste:
import { basicSetup, EditorView } from 'codemirror';
import { vim } from "@replit/codemirror-vim"

let view = new EditorView({
  doc: "",
  extensions: [
    // make sure vim is included before other keymaps
    vim(), 
    // include the default keymap and all other keymaps you want to use in insert mode
    basicSetup, 
  ],
  parent: document.querySelector('#editor'),
})

Understanding the vim() function

The vim() function returns a CodeMirror extension that adds Vim keybindings to your editor. It accepts an optional configuration object:
vim(options?: { status?: boolean })

Options

  • status (boolean, optional): When true, displays a status bar showing the current Vim mode (e.g., “—NORMAL—”, “—INSERT—”). Defaults to false.

Example with status bar

let view = new EditorView({
  doc: "",
  extensions: [
    vim({ status: true }), // Enable status bar
    basicSetup,
  ],
  parent: document.querySelector('#editor'),
})

Important notes

If you’re not using basicSetup, make sure you include the drawSelection plugin to correctly render the selection in visual mode.

Extension ordering matters

The Vim extension must come before other keymaps in the extensions array:
// ✅ Correct: vim() comes first
extensions: [vim(), basicSetup]

// ❌ Incorrect: other keymaps before vim
extensions: [basicSetup, vim()]
This ordering ensures that:
  • Vim keybindings work correctly in normal mode
  • Default keybindings (from basicSetup) remain available in insert mode
  • Other custom keymaps can coexist with Vim bindings

Next steps

Now that you have a working Vim-enabled editor, explore advanced features:

Customization

Learn how to customize keybindings and ex commands

Vim API

Access the Vim API to programmatically control the editor

Build docs developers (and LLMs) love