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:
npmto 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.
esbuildwill parse the JavaScript module we wrote, find the code it depends on (that we installed withnpm) and pull it all together- the
--minifyflag tellsesbuildto minify our code - the
--bundleflag tellsesbuildto concatenate all the packages (in our case,codemirrorand any plugins we installed) into a single file main.jsis the name of our script--outfile=editor.jstellsesbuildwhere 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.jsscript thatesbuildbuilt 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.