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:
npm
to get the pieces we'll need- esbuild to put the pieces together for us
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
.
esbuild
will parse the JavaScript module we wrote, find the code it depends on (that we installed withnpm
) and pull it all together- the
--minify
flag tellsesbuild
to minify our code - the
--bundle
flag tellsesbuild
to concatenate all the packages (in our case,codemirror
and any plugins we installed) into a single file main.js
is the name of our script--outfile=editor.js
tellsesbuild
where to put all this code once it's compiled
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:
- a form with a textarea that we're going to submit
- the
editor.js
script thatesbuild
built for us
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.