codemirror 6 and textareas

With codemirror 5 you can use CodeMirror.fromTextArea() to create an editor from a tag which I really like since it lets users without JS still do things and makes it easier to send data with an html form.

I can’t find any mention of s in the cm 6 manual. Is it possible at this point in time to support users without JS and/or post data with an html form?

This was always a dodgy hack (it involves replacing the surrounding form’s submit method, among other things) that leaks quite a bit (for example if you expect your textarea’s value to be kept in sync with the editor content), so I’m kind of happy to get away from it. It’d be easy to write something similar as a separate module, of course.

For anyone who stumbles across this thread in the future, here’s how I ended up solving it. It might be better suited as an extension(?), but this works pretty well and I’ve yet to run into issues with this method.

HTML:

<form>
    <div id="editorTarget"></div>
    <textarea id="editorSource" name="editorSource">Some filler text</textarea>
    <button id="submit" type="submit">Submit</button>
</form>

JS:

import { EditorState } from "@codemirror/state";
import { EditorView, keymap } from "@codemirror/view";
import { defaultKeymap } from "@codemirror/commands";

// Find the submit button
const submitButton = document.querySelector("#submit");

// Hide the textarea used as the editor's source
const editorSource = document.querySelector("#editorSource");
editorSource.setAttribute("hidden", "true");

// Find the editor targtet
const editorTarget = document.querySelector("#editorTarget");

// Set up Code mirror
let startState = EditorState.create({
  // Use the textarea's value as the initial text for CodeMirror
  doc: editorSource.value,
  extensions: [keymap.of(defaultKeymap)],
});

let view = new EditorView({
  state: startState,
  parent: editorTarget,
});

// Sync the contents of CodeMirror with the textarea
const syncEditor = () => {
  // Is there a better way to get CodeMirror's contents?
  // Not sure, but `view.state.sliceDoc()` was the easiest way I found.
  editorSource.value = view.state.sliceDoc();
  console.log(editorSource.value);
};

submitButton.addEventListener("click", syncEditor);