Posted on

Using monaco editor for HTML form textarea

For one of my personal projects I wanted to have a more convenient way to edit markdown in an HTML form, than the plain text. I ended up with using the Monaco Editor that powers VS Code, as the form editor.

My form is a really basic one — just a single <textarea> element, and a submit button:

<form method="POST" id="MyForm">
    <input required id="text" name="text">
    <input type="submit" value="Save" id="submitButton">
</form>

monaco-editor-samples repository contains a lot of examples on how one can include Monaco editor onto their page, so I just picked one of the examples.

While code samples and Monaco editor playground demonstrated certain bits of functionality, none of the fits my use case exactly, so I had to figure out how to match different features together.

What I wanted to get:

  1. Full page editor area, if possible, without submit button in the way, and form submitting on some shortcut/hotkey.
  2. Editor area size should follow browser page resize, both vertically and horizontally.
  3. Editor color scheme should follow user's light/dark theme preference.

After reading many examples, lots of trial and error, I ended up with the working solution that implemented all of the requirements.

The code below implements a single-field HTML form, you can edit markdown text and submit the form with the “Ctrl-s” or “Cmd-s” shortcuts. You can see it as a standalone demo.

<!doctype html><head><meta charset="utf-8"><title>Editor</title>
    <style>
        html,body{margin: 0; padding: 0;}
        div#editor {height: 100vh; box-sizing: border-box; overflow: hidden;}
    </style>
</head>
<body>
    <form method="POST" id="MyForm">
        <div id="editor"></div>
        <input required type="hidden" id="text" name="text">
    </form>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.27.0/min/vs/loader.min.js" integrity="sha512-SExj71Cw3B9C9EE8BC/ad3AKia5zQXDj/2SM4THgkeKh5GIFZhKM/R3uclUG8YZwJrjcVhydAlIHmfNvsBCKZA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
    require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.27.0/min/vs' }});
    require(['vs/editor/editor.main'], function() {
        let theme = "vs";
        if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
            theme = "vs-dark";
        }
        window.editor = monaco.editor.create(document.getElementById('editor'), {
            value: "# Document Header\n\nEnter some text, submit the form with Ctrl-s or Cmd-s shortcut.",
            language: 'markdown',
            lineNumbers: "off",
            wordWrap: "bounded",
            wordWrapColumn: 100,
            wrappingIndent: "same",
            fontSize: 14,
            roundedSelection: false,
            scrollBeyondLastLine: false,
            quickSuggestions: false,
            minimap: {enabled:false},
            theme: theme,
        });

        window.editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S, function() {
            var inp = document.getElementById('text');
            inp.value = window.editor.getValue();
            document.forms['MyForm'].submit();
        });

        window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", e => {
            if (e.matches) {
                monaco.editor.setTheme("vs-dark");
            } else {
                monaco.editor.setTheme("vs");
            }
        })

        const divElem = document.getElementById('editor');
        const resizeObserver = new ResizeObserver(entries => {
            window.editor.layout();
        });
        resizeObserver.observe(divElem);
    });
</script>
</body>