<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>vanillajs &amp;mdash; Nat Knight</title>
    <link>http://natknight.xyz/tag:vanillajs</link>
    <description>Reflections, diversions, and opinions from a progressive ex-physicist programmer dad with a sore back.</description>
    <pubDate>Fri, 22 May 2026 15:31:35 -0700</pubDate>
    <item>
      <title>Replace a textarea with CodeMirror in 30 lines of code and 30 minutes</title>
      <link>http://natknight.xyz/replace-a-textarea-with-codemirror-in-30-lines-of-code-and-30-minutes</link>
      <description>&lt;![CDATA[#codemirror #webdev #vanillajs #esbuild&#xA;&#xA;When you write an HTML form, [textarea] is the standard way to support multi-line input, but it&#39;s not suitable for every application. [CodeMirror] describes itself as a &#34;code editor component for the web&#34;, and might be a suitable replacement for a textarea if you want something more like a code editor.&#xA;&#xA;[textarea]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea&#xA;[CodeMirror]: https://codemirror.net/&#xA;&#xA;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&#39;s no harder to deploy than vanilla JavaScript and HTML.&#xA;&#xA;You can also jump straight to the [source code] if you prefer.&#xA;&#xA;[source code]: https://github.com/nathanielknight/codemirror-in-30&#xA;&#xA;!--more--&#xA;&#xA;Tooling&#xA;&#xA;In the spirit of [A simple stack for today&#39;s web hacks] (which was part of the inspiration for this guide) we&#39;ll try to keep our tooling to a minimum:&#xA;&#xA;npm to get the pieces we&#39;ll need&#xA;[esbuild] to put the pieces together for us&#xA;&#xA;We&#39;ll even install esbuild using npm, so that&#39;s all you&#39;ll need in order to get started (there are many ways to install it; I happen to like [Volta]).&#xA;&#xA;[Volta]: https://volta.sh/&#xA;&#xA;[A simple stack for today&#39;s web hacks]: https://neugierig.org/software/blog/2022/12/simple-web-hacks.html&#xA;[esbuild]: https://esbuild.github.io/&#xA;&#xA;Dependencies&#xA;&#xA;In the project you want to add your CodeMirror editor to, run&#xA;&#xA;npm init&#xA;npm add codemirror&#xA;npm add --save-dev esbuild&#xA;&#xA;This will let you set up a very basic editor and bundle it so it&#39;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&#39;ll add [markdown syntax highlighting]&#xA;&#xA;[first party]: https://codemirror.net/docs/extensions/&#xA;[community developed]: https://codemirror.net/docs/community/&#xA;[markdown syntax highlighting]: https://www.npmjs.com/package/@codemirror/lang-markdown&#xA;&#xA;npm add @codemirror/lang-markdown&#xA;&#xA;Code&#xA;&#xA;Once your packages are installed its time to set up the editor. Create a file with these contents (I called my main.js).&#xA;&#xA;import { basicSetup, EditorView } from &#34;codemirror&#34;&#xA;import { markdown } from &#34;@codemirror/lang-markdown&#34;&#xA;&#xA;// Hide the existing textarea&#xA;let textarea = document.querySelector(&#39;textarea&#39;);&#xA;textarea.style.display = &#34;none&#34;;&#xA;&#xA;// Create a CodeMirror editor with the textarea&#39;s contents&#xA;let view = new EditorView({&#xA;    doc: textarea.value,&#xA;    extensions: [&#xA;        basicSetup,&#xA;        markdown({}),&#xA;    ],&#xA;});&#xA;// Insert the editor into the document&#xA;textarea.insertAdjacentElement(&#34;afterend&#34;, view.dom);&#xA;&#xA;// When submitting the form, update the textarea with the editor&#39;s&#xA;// contents so that they&#39;re included with the form submission.&#xA;textarea.parentElement.onsubmit = function () {&#xA;    textarea.value = view.state.doc;&#xA;}&#xA;&#xA;This is what we&#39;re going to &#34;build&#34; with esbuild and eventually add to our web page.&#xA;&#xA;Build&#xA;&#xA;To create the final JavaScript file that we&#39;re going to include on our web page, run&#xA;&#xA;npm run esbuild --minify --bundle main.js --outfile=editor.js&#xA;&#xA;npm run is a helper command that executes programs installed with NPM, so really we&#39;re running esbuild --minify --bundle main.js --outfile=editor.js.&#xA;&#xA;esbuild will parse the JavaScript module we wrote, find the code it depends on (that we installed with npm) and pull it all together&#xA;the --minify flag tells esbuild to minify our code&#xA;the --bundle flag tells esbuild to concatenate all the packages (in our case, codemirror and any plugins we installed) into a single file&#xA;main.js is the name of our script&#xA;--outfile=editor.js tells esbuild where to put all this code once it&#39;s compiled&#xA;&#xA;Publish&#xA;&#xA;Finally, let&#39;s publish our editor. Here&#39;s a basic HTML file to load it:&#xA;&#xA;!DOCTYPE html&#xA;html lang=&#34;en&#34;&#xA;&#xA;head&#xA;    meta charset=&#34;UTF-8&#34;&#xA;    meta http-equiv=&#34;X-UA-Compatible&#34; content=&#34;IE=edge&#34;&#xA;    meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&#xA;    titleCodeMirror in 30/title&#xA;/head&#xA;&#xA;body&#xA;    form action=&#34;&#34;&#xA;        label for=&#34;editor&#34;Editor Input/label&#xA;        textarea name=&#34;editor&#34;/textarea&#xA;    /form&#xA;    script src=&#34;editor.js&#34;/script&#xA;    /form&#xA;/body&#xA;&#xA;/html&#xA;&#xA;This document has:&#xA;&#xA;a form with a textarea that we&#39;re going to submit&#xA;the editor.js script that esbuild built for us&#xA;&#xA;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.&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="http://natknight.xyz/tag:codemirror" class="hashtag"><span>#</span><span class="p-category">codemirror</span></a> <a href="http://natknight.xyz/tag:webdev" class="hashtag"><span>#</span><span class="p-category">webdev</span></a> <a href="http://natknight.xyz/tag:vanillajs" class="hashtag"><span>#</span><span class="p-category">vanillajs</span></a> <a href="http://natknight.xyz/tag:esbuild" class="hashtag"><span>#</span><span class="p-category">esbuild</span></a></p>

<p>When you write an HTML form, <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea"><code>textarea</code></a> is the standard way to support multi-line input, but it&#39;s not suitable for every application. <a href="https://codemirror.net/">CodeMirror</a> describes itself as a “code editor component for the web”, and might be a suitable replacement for a <code>textarea</code> if you want something more like a code editor.</p>

<p>This article describes how to replace a <code>textarea</code> 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&#39;s no harder to deploy than vanilla JavaScript and HTML.</p>

<p>You can also jump straight to the <a href="https://github.com/nathanielknight/codemirror-in-30">source code</a> if you prefer.</p>



<h2 id="tooling" id="tooling">Tooling</h2>

<p>In the spirit of <a href="https://neugierig.org/software/blog/2022/12/simple-web-hacks.html">A simple stack for today&#39;s web hacks</a> (which was part of the inspiration for this guide) we&#39;ll try to keep our tooling to a minimum:</p>
<ul><li><code>npm</code> to get the pieces we&#39;ll need</li>
<li><a href="https://esbuild.github.io/">esbuild</a> to put the pieces together for us</li></ul>

<p>We&#39;ll even install <code>esbuild</code> using <code>npm</code>, so that&#39;s all you&#39;ll need in order to get started (there are many ways to install it; I happen to like <a href="https://volta.sh/">Volta</a>).</p>

<h2 id="dependencies" id="dependencies">Dependencies</h2>

<p>In the project you want to add your CodeMirror editor to, run</p>

<pre><code class="language-shell">npm init
npm add codemirror
npm add --save-dev esbuild
</code></pre>

<p>This will let you set up a very basic editor and bundle it so it&#39;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 <a href="https://codemirror.net/docs/extensions/">first party</a> and <a href="https://codemirror.net/docs/community/">community developed</a>). They can also be installed with <code>npm add</code> and added to the editor initialization script below. For this example, we&#39;ll add <a href="https://www.npmjs.com/package/@codemirror/lang-markdown">markdown syntax highlighting</a></p>

<pre><code class="language-shell">npm add @codemirror/lang-markdown
</code></pre>

<h2 id="code" id="code">Code</h2>

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

<pre><code class="language-javascript">import { basicSetup, EditorView } from &#34;codemirror&#34;
import { markdown } from &#34;@codemirror/lang-markdown&#34;

// Hide the existing textarea
let textarea = document.querySelector(&#39;textarea&#39;);
textarea.style.display = &#34;none&#34;;

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

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

<p>This is what we&#39;re going to “build” with <code>esbuild</code> and eventually add to our web page.</p>

<h2 id="build" id="build">Build</h2>

<p>To create the final JavaScript file that we&#39;re going to include on our web page, run</p>

<pre><code class="language-shell">npm run esbuild --minify --bundle main.js --outfile=editor.js
</code></pre>

<p><code>npm run</code> is a helper command that executes programs installed with NPM, so really we&#39;re running <code>esbuild --minify --bundle main.js --outfile=editor.js</code>.</p>
<ul><li><code>esbuild</code> will parse the JavaScript module we wrote, find the code it depends on (that we installed with <code>npm</code>) and pull it all together</li>
<li>the <code>--minify</code> flag tells <code>esbuild</code> to minify our code</li>
<li>the <code>--bundle</code> flag tells <code>esbuild</code> to concatenate all the packages (in our case, <code>codemirror</code> and any plugins we installed) into a single file</li>
<li><code>main.js</code> is the name of our script</li>
<li><code>--outfile=editor.js</code> tells <code>esbuild</code> where to put all this code once it&#39;s compiled</li></ul>

<h2 id="publish" id="publish">Publish</h2>

<p>Finally, let&#39;s publish our editor. Here&#39;s a basic HTML file to load it:</p>

<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;

&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta http-equiv=&#34;X-UA-Compatible&#34; content=&#34;IE=edge&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;CodeMirror in 30&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;form action=&#34;&#34;&gt;
        &lt;label for=&#34;editor&#34;&gt;Editor Input&lt;/label&gt;
        &lt;textarea name=&#34;editor&#34;&gt;&lt;/textarea&gt;
    &lt;/form&gt;
    &lt;script src=&#34;editor.js&#34;&gt;&lt;/script&gt;
    &lt;/form&gt;
&lt;/body&gt;

&lt;/html&gt;
</code></pre>

<p>This document has:</p>
<ul><li>a form with a textarea that we&#39;re going to submit</li>
<li>the <code>editor.js</code> script that <code>esbuild</code> built for us</li></ul>

<p>When the page is first loaded, we mark the <code>textarea</code> as hidden and append a CodeMirror editor to the form. As the form gets submitted, we copy the contents of the editor into the <code>textarea</code> so that it gets sent along with the rest of the form.</p>
]]></content:encoded>
      <guid>http://natknight.xyz/replace-a-textarea-with-codemirror-in-30-lines-of-code-and-30-minutes</guid>
      <pubDate>Sat, 07 Jan 2023 08:00:00 +0000</pubDate>
    </item>
  </channel>
</rss>