Nathaniel Knight

Reflections, diversions, and opinions from a progressive ex-physicist programmer dad with a sore back.

Replace a textarea with CodeMirror in 30 lines of code and 30 minutes

When you write an HTML form, textarea is the standard way to support multi-line input, but it's not suitable for every application. CodeMirror describes itself as a "code editor component for the web", and might be a suitable replacement for a textarea if you want something more like a code editor.

This article describes how to replace a textarea with a CodeMirror editor in under 30 lines of code and (hopefully) under 30 minutes of effort. It uses some very basic tooling to create an artifact that's no harder to deploy than vanilla JavaScript and HTML.

You can also jump straight to the source code if you prefer.

Tooling

In the spirit of A simple stack for today's web hacks (which was part of the inspiration for this guide) we'll try to keep our tooling to a minimum:

We'll even install esbuild using npm, so that's all you'll need in order to get started (there are many ways to install it; I happen to like Volta).

Dependencies

In the project you want to add your CodeMirror editor to, run

npm init
npm add codemirror
npm add --save-dev esbuild

This will let you set up a very basic editor and bundle it so it's easy to deploy. If you want to add features (syntax highlighting, Vim or Emacs keybindings, integration with Vue or Svelte, etc.) there are many extensions (both first party and community developed). They can also be installed with npm add and added to the editor initialization script below. For this example, we'll add markdown syntax highlighting

npm add @codemirror/lang-markdown

Code

Once your packages are installed its time to set up the editor. Create a file with these contents (I called my main.js).

import { basicSetup, EditorView } from "codemirror"
import { markdown } from "@codemirror/lang-markdown"

// Hide the existing textarea
let textarea = document.querySelector('textarea');
textarea.style.display = "none";

// Create a CodeMirror editor with the textarea's contents
let view = new EditorView({
    doc: textarea.value,
    extensions: [
        basicSetup,
        markdown({}),
    ],
});
// Insert the editor into the document
textarea.insertAdjacentElement("afterend", view.dom);

// When submitting the form, update the textarea with the editor's
// contents so that they're included with the form submission.
textarea.parentElement.onsubmit = function () {
    textarea.value = view.state.doc;
}

This is what we're going to "build" with esbuild and eventually add to our web page.

Build

To create the final JavaScript file that we're going to include on our web page, run

npm run esbuild --minify --bundle main.js --outfile=editor.js

npm run is a helper command that executes programs installed with NPM, so really we're running esbuild --minify --bundle main.js --outfile=editor.js.

Publish

Finally, let's publish our editor. Here's a basic HTML file to load it:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CodeMirror in 30</title>
</head>

<body>
    <form action="">
        <label for="editor">Editor Input</label>
        <textarea name="editor"></textarea>
    </form>
    <script src="editor.js"></script>
    </form>
</body>

</html>

This document has:

When the page is first loaded, we mark the textarea as hidden and append a CodeMirror editor to the form. As the form gets submitted, we copy the contents of the editor into the textarea so that it gets sent along with the rest of the form.